<commit_before>'use strict';

describe('juju application notifications', function() {
  var _setTimeout, _viewsHighlightRow, db, ERR_EV, juju, models, NO_OP,
      viewContainer, views, Y;

  before(function(done) {
    Y = YUI(GlobalConfig).use(['node',
      'juju-models',
      'juju-views',
      'juju-gui',
      'juju-env',
      'juju-tests-utils',
      'node-event-simulate'],
    function(Y) {
      juju = Y.namespace('juju');
      models = Y.namespace('juju.models');
      views = Y.namespace('juju.views');
      done();
    });

    ERR_EV = {
      err: true
    };
    NO_OP = function() {};
  });

  beforeEach(function(done) {
    Y = YUI(GlobalConfig).use(['node',
      'juju-models',
      'juju-views',
      'juju-gui',
      'juju-env',
      'juju-tests-utils',
      'node-event-simulate'],
    function(Y) {
      viewContainer = Y.Node.create('<div />');
      viewContainer.appendTo(Y.one('body'));
      viewContainer.hide();

      db = new models.Database();

      // The notifications.js delays the notification update.
      // We are going to avoid this timeout to make it possible to test
      // the notification callback synchronously.
      _setTimeout = window.setTimeout;
      window.setTimeout = function(callback) {
        callback();
      };

      // We skip this part because we have no row to highlight
      _viewsHighlightRow = views.highlightRow;
      views.highlightRow = NO_OP;
      done();
    });
  });

  afterEach(function() {
    viewContainer.remove(true);
    window.setTimeout = _setTimeout;
    views.highlightRow = _viewsHighlightRow;
  });

  it('should notify errors in the notifications view', function() {
    viewContainer.set('id', 'notifications');
    var notificationsView = new views.NotificationsView({
      container: viewContainer,
      env: {
        on: NO_OP,
        get: function(key) {
          if (key === 'connected') {
            return true;
          }
          return null;
        }
      },
      notifications: db.notifications
    });
    notificationsView.render();
    var notification = new models.Notification({level: 'error'});
    db.notifications.add(notification);
    assert.equal('1', viewContainer.one('#notify-indicator').getHTML().trim());
  });

  it('should show notification for "add_unit" and "remove_units" exceptions' +
     ' (service view)', function() {
       var view = new views.service(
       { container: viewContainer,
         getModelURL: function() {
           return 'my url';
         },
         db: db,
         env: {
           add_unit: function(serviceId, delta, callback) {
             callback(ERR_EV);
           },
           remove_units: function(param, callback) {
             callback(ERR_EV);
           }
         },
         model: {
           getAttrs: NO_OP,
           get: function(key) {
             if ('unit_count' === key) {
               // We simulate a model with 2 units
               return 2;
             }
             return null;
           }
         },
         querystring: {}}).render();

       db.units.get_units_for_service = function() {
         return [{
           id: 1
         }];
       };

       // It triggers the "add unit" logic
       view._modifyUnits(3);
       assert.equal(1, db.notifications.size());

       // It triggers the "remove unit" logic
       view._modifyUnits(1);
       assert.equal(2, db.notifications.size());
     });

  it('should show notification for "remove_units" and "resolved" exceptions' +
      ' (unit view)', function()
     {
       var view = new views.unit(
       { container: viewContainer,
         getModelURL: function() {return 'my url';},
         db: db,
         env: {
           remove_units: function(param, callback) {
             callback(
             { err: true,
               unit_names: ['aaa']});
           },
           resolved: function(unit_name, relation_name, retry, callback) {
             callback(ERR_EV);
           }},
         unit: {},
         querystring: {}
       });

        // Used by "unit.js" inside the "render" function
        db.services.getById = function() {
          // Mock service
          return {
            get: function(key) {
              if (key === 'loaded') {
                return true;
              }
              return null;
            }
          };
        };

        view.render();

        view.confirmRemoved({
          preventDefault: NO_OP
        });

        view.remove_panel.footerNode.one('.btn-danger').simulate('click');
        view.remove_panel.destroy();

        assert.equal(1, db.notifications.size());

        // Fake relation
        db.relations.getById = function() {
          return {name: ''};
        };

        view.retryRelation({
          preventDefault: NO_OP,

          // This is a mock object of the relation button
          target: {
            ancestor: function() {
              return {get: NO_OP};
            },
            set: NO_OP
          }
        });

        assert.equal(2, db.notifications.size());
      });

  it('should add a notification for "addRelation" exceptions (env view)',
      function() {
        var view = new views.environment({db: db, container: viewContainer});
        view.render();
        var module = view.topo.modules.RelationModule;
        // The callback wants to remove the pending relation from the db.
        db.relations.remove = NO_OP;
        // The _addRelationCallback args are: view, relation id, event.
        var args = [module, 'relation_id', ERR_EV];
        module._addRelationCallback.apply(module, args);
        assert.equal(1, db.notifications.size());
      });

  it('should add a notification for "removeRelation" exceptions (env view)',
      function() {
        var view = new views.environment({db: db, container: viewContainer});
        view.render();
        var module = view.topo.modules.RelationModule;
        // The _removeRelationCallback args are: view, relation element,
        // relation id, confirm button, event.
        var args = [
          {get: function() {return {hide: NO_OP, destroy: NO_OP};},
           removeSVGClass: NO_OP
          }, {}, 'relation_id', {set: NO_OP}, ERR_EV
        ];
        module._removeRelationCallback.apply(module, args);
        assert.equal(1, db.notifications.size());
      });

  it('should add a notification for "destroyService" exceptions (env view)',
      function() {
        var view = new views.environment({db: db, container: viewContainer});
        view.render();
        var module = view.topo.modules.ServiceModule;
        // The callback uses the 'getModelURL' attribute to retrieve the
        // service URL.
        module.set('getModelURL', NO_OP);
        // The _destroyCallback args are: service, view, confirm button, event.
        var args = [{}, module, {set: NO_OP}, ERR_EV];
        module.service_click_actions._destroyCallback.apply(module, args);
        assert.equal(1, db.notifications.size());
      });

  it('should show notification for "get_service" exceptions' +
      ' (service constraints view)', function() {

        var view = new views.service_constraints(
            { model:
             { getAttrs: NO_OP,
               get: function(key) {
                 if ('constraints' === key) {
                   return {};
                 }
                 return null;
               }},
              getModelURL: NO_OP,
              db: db,
              env:
                  { set_constraints: function(id, values, callback) {
                    callback(ERR_EV);
                  }},
              container: viewContainer}).render();

        view.updateConstraints();

        assert.equal(1, db.notifications.size());
      });

  it('should show notification for "get_service", "expose" and "unexpose"' +
      ' exceptions (service config view)', function() {

        var view = new views.service_config(
       { db: db,
         env: {
           set_config: function(id, newValues, callback) {
             callback(ERR_EV);
           },
           expose: function(id, callback) {
             callback(ERR_EV);
           },
           unexpose: function(id, callback) {
             callback({err: true, service_name: '1234'});
           }
         },
         getModelURL: NO_OP,
         model: {
           getAttrs: NO_OP,
           get: function(key) {
             if ('loaded' === key) {
               return true;
             }
             if ('config' === key) {
               return {};
             }
             return null;
           }},
         container: viewContainer});

        db.services.getById = NO_OP;
        db.charms.getById = function() {
          return {
            getAttrs: function() {
              return {};
            },
            get: function(key) {
              if ('config' === key) {
                return {};
              }
              return null;
            }
          };
        };
        view.render();

        view.saveConfig();
        assert.equal(1, db.notifications.size());

        view.exposeService();
        assert.equal(2, db.notifications.size());

        view.unexposeService();
        assert.equal(3, db.notifications.size());
      });

  it('should show notification for "remove_relation"' +
      ' exceptions (service relations view)', function() {

        var view = new views.service_relations(
       { db: db,
         env: {
           remove_relation: function(id, newValues, callback) {
             callback(ERR_EV);
           }
         },
         getModelURL: NO_OP,
         container: viewContainer});

        db.relations.getById = function() {
          return {
            get: function(key) {
              if ('endpoints' === key) {
                return [
                  [{}, {name: ''}]
                ];
              }
              return null;
            }
          };
        };

        view.render();

        view.confirmRemoved({
          preventDefault: NO_OP,

          // This is a mock object of the relation button
          target: {
            ancestor: NO_OP,
            get: NO_OP
          }
        });
        view.remove_panel.footerNode.one('.btn-danger').simulate('click');
        view.remove_panel.destroy();

        assert.equal(1, db.notifications.size());
      });

  it('should show notification for "deploy" exceptions (charm view)',
      function() {
        var notified = false,
       db = {
         notifications: {
           add: function() {
             // This method should be called just once.
             assert.isFalse(notified);
             notified = true;
           }
         }
       },
       charm = {},
       container = {
         all: function() {
           return {each: NO_OP};
         },
         one: function() {
           return {get: NO_OP};
         }
       },
       env = {
         deploy: function(charmUrl, serviceName, config, callback) {
           callback(ERR_EV);
         }
       },
       mockView = {
         fire: NO_OP,
         _deployCallback: function() {
           // Executing the "views.charm.prototype._deployCallback"
           // function instead. The "views.charm.prototype._deployCallback"
           // is the one that will trigger the notification process.
           views.charm.prototype._deployCallback.apply(this, arguments);
         },
         get: function(key) {
           if ('charm' === key) {
             return charm;
           }
           if ('container' === key) {
             return container;
           }
           if ('db' === key) {
             return db;
           }
           if ('env' === key) {
             return env;
           }
           return null;
         }
       };

        views.charm.prototype.on_charm_deploy.apply(mockView, [ERR_EV]);
        assert.isTrue(notified);
      });

  it('should show errors for no unit, one unit and multiple ' +
      'units (service view)', function() {
        //_removeUnitCallback
        var mockView =
            { get: function(key) {
              return {
           getModelURL: NO_OP,
           db:
           { fire: NO_OP,
             notifications:
             { add: function(notification) {
               messages.push(notification.get('message'));
               titles.push(notification.get('title'));
             }}}}[key];
       }},
       messages = [],
       titles = [],
       baseView = new views.serviceBase({});

        baseView._removeUnitCallback.apply(mockView, [{
          err: true,
          unit_names: null
        }]);

        baseView._removeUnitCallback.apply(mockView, [{
          err: true,
          unit_names: []
        }]);

        baseView._removeUnitCallback.apply(mockView, [{
          err: true,
          unit_names: ['a']
        }]);

        baseView._removeUnitCallback.apply(mockView, [{
          err: true,
          unit_names: ['b', 'c']
        }]);

        function assertTrace(expected, trace) {
          assert.equal(expected.join(';'), trace.join(';'));
        }

        assertTrace(['Error removing unit', 'Error removing unit',
          'Error removing unit', 'Error removing units'], titles);
        assertTrace(['', '', 'Unit name: a', 'Unit names: b, c'], messages);
      });

});
<commit_msg>Fixed failing test.<commit_after>'use strict';

describe('juju application notifications', function() {
  var _setTimeout, _viewsHighlightRow, db, ERR_EV, juju, models, NO_OP,
      viewContainer, views, Y;

  before(function(done) {
    Y = YUI(GlobalConfig).use(['node',
      'juju-models',
      'juju-views',
      'juju-gui',
      'juju-env',
      'juju-tests-utils',
      'node-event-simulate'],
    function(Y) {
      juju = Y.namespace('juju');
      models = Y.namespace('juju.models');
      views = Y.namespace('juju.views');
      done();
    });

    ERR_EV = {
      err: true
    };
    NO_OP = function() {};
  });

  beforeEach(function(done) {
    Y = YUI(GlobalConfig).use(['node',
      'juju-models',
      'juju-views',
      'juju-gui',
      'juju-env',
      'juju-tests-utils',
      'node-event-simulate'],
    function(Y) {
      viewContainer = Y.Node.create('<div />');
      viewContainer.appendTo(Y.one('body'));
      viewContainer.hide();

      db = new models.Database();

      // The notifications.js delays the notification update.
      // We are going to avoid this timeout to make it possible to test
      // the notification callback synchronously.
      _setTimeout = window.setTimeout;
      window.setTimeout = function(callback) {
        callback();
      };

      // We skip this part because we have no row to highlight
      _viewsHighlightRow = views.highlightRow;
      views.highlightRow = NO_OP;
      done();
    });
  });

  afterEach(function() {
    viewContainer.remove(true);
    window.setTimeout = _setTimeout;
    views.highlightRow = _viewsHighlightRow;
  });

  it('should notify errors in the notifications view', function() {
    viewContainer.set('id', 'notifications');
    var notificationsView = new views.NotificationsView({
      container: viewContainer,
      env: {
        on: NO_OP,
        get: function(key) {
          if (key === 'connected') {
            return true;
          }
          return null;
        }
      },
      notifications: db.notifications
    });
    notificationsView.render();
    var notification = new models.Notification({level: 'error'});
    db.notifications.add(notification);
    assert.equal('1', viewContainer.one('#notify-indicator').getHTML().trim());
  });

  it('should show notification for "add_unit" and "remove_units" exceptions' +
     ' (service view)', function() {
       var view = new views.service(
       { container: viewContainer,
         getModelURL: function() {
           return 'my url';
         },
         db: db,
         env: {
           add_unit: function(serviceId, delta, callback) {
             callback(ERR_EV);
           },
           remove_units: function(param, callback) {
             callback(ERR_EV);
           }
         },
         model: {
           getAttrs: NO_OP,
           get: function(key) {
             if ('unit_count' === key) {
               // We simulate a model with 2 units
               return 2;
             }
             return null;
           }
         },
         querystring: {}}).render();

       db.units.get_units_for_service = function() {
         return [{
           id: 1
         }];
       };

       // It triggers the "add unit" logic
       view._modifyUnits(3);
       assert.equal(1, db.notifications.size());

       // It triggers the "remove unit" logic
       view._modifyUnits(1);
       assert.equal(2, db.notifications.size());
     });

  it('should show notification for "remove_units" and "resolved" exceptions' +
      ' (unit view)', function()
     {
       var view = new views.unit(
       { container: viewContainer,
         getModelURL: function() {return 'my url';},
         db: db,
         env: {
           remove_units: function(param, callback) {
             callback(
             { err: true,
               unit_names: ['aaa']});
           },
           resolved: function(unit_name, relation_name, retry, callback) {
             callback(ERR_EV);
           }},
         unit: {},
         querystring: {}
       });

        // Used by "unit.js" inside the "render" function
        db.services.getById = function() {
          // Mock service
          return {
            get: function(key) {
              if (key === 'loaded') {
                return true;
              }
              return null;
            }
          };
        };

        view.render();

        view.confirmRemoved({
          preventDefault: NO_OP
        });

        view.remove_panel.footerNode.one('.btn-danger').simulate('click');
        view.remove_panel.destroy();

        assert.equal(1, db.notifications.size());

        // Fake relation
        db.relations.getById = function() {
          return {name: ''};
        };

        view.retryRelation({
          preventDefault: NO_OP,

          // This is a mock object of the relation button
          target: {
            ancestor: function() {
              return {get: NO_OP};
            },
            set: NO_OP
          }
        });

        assert.equal(2, db.notifications.size());
      });

  it('should add a notification for "addRelation" exceptions (env view)',
      function() {
        var view = new views.environment({db: db, container: viewContainer});
        view.render();
        var module = view.topo.modules.RelationModule;
        // The callback wants to remove the pending relation from the db.
        db.relations.remove = NO_OP;
        // The _addRelationCallback args are: view, relation id, event.
        var args = [module, 'relation_id', ERR_EV];
        module._addRelationCallback.apply(module, args);
        assert.equal(1, db.notifications.size());
      });

  it('should add a notification for "removeRelation" exceptions (env view)',
      function() {
        var view = new views.environment({db: db, container: viewContainer});
        view.render();
        var module = view.topo.modules.RelationModule;
        // The _removeRelationCallback args are: view, relation element,
        // relation id, confirm button, event.
        var args = [
          {get: function() {return {hide: NO_OP, destroy: NO_OP};},
           removeSVGClass: NO_OP
          }, {}, 'relation_id', {set: NO_OP}, ERR_EV
        ];
        module._removeRelationCallback.apply(module, args);
        assert.equal(1, db.notifications.size());
      });

  it('should add a notification for "destroyService" exceptions (env view)',
      function() {
        var view = new views.environment({db: db, container: viewContainer});
        view.render();
        // The callback uses the 'getModelURL' attribute to retrieve the
        // service URL.
        view.topo.set('getModelURL', NO_OP);
        var module = view.topo.modules.ServiceModule;
        // The callback hides the destroy dialog at the end of the process.
        module.set('destroy_dialog', {hide: NO_OP});
        // The _destroyCallback args are: service, view, confirm button, event.
        var args = [{}, module, {set: NO_OP}, ERR_EV];
        module.service_click_actions._destroyCallback.apply(module, args);
        assert.equal(1, db.notifications.size());
      });

  it('should show notification for "get_service" exceptions' +
      ' (service constraints view)', function() {

        var view = new views.service_constraints(
            { model:
             { getAttrs: NO_OP,
               get: function(key) {
                 if ('constraints' === key) {
                   return {};
                 }
                 return null;
               }},
              getModelURL: NO_OP,
              db: db,
              env:
                  { set_constraints: function(id, values, callback) {
                    callback(ERR_EV);
                  }},
              container: viewContainer}).render();

        view.updateConstraints();

        assert.equal(1, db.notifications.size());
      });

  it('should show notification for "get_service", "expose" and "unexpose"' +
      ' exceptions (service config view)', function() {

        var view = new views.service_config(
       { db: db,
         env: {
           set_config: function(id, newValues, callback) {
             callback(ERR_EV);
           },
           expose: function(id, callback) {
             callback(ERR_EV);
           },
           unexpose: function(id, callback) {
             callback({err: true, service_name: '1234'});
           }
         },
         getModelURL: NO_OP,
         model: {
           getAttrs: NO_OP,
           get: function(key) {
             if ('loaded' === key) {
               return true;
             }
             if ('config' === key) {
               return {};
             }
             return null;
           }},
         container: viewContainer});

        db.services.getById = NO_OP;
        db.charms.getById = function() {
          return {
            getAttrs: function() {
              return {};
            },
            get: function(key) {
              if ('config' === key) {
                return {};
              }
              return null;
            }
          };
        };
        view.render();

        view.saveConfig();
        assert.equal(1, db.notifications.size());

        view.exposeService();
        assert.equal(2, db.notifications.size());

        view.unexposeService();
        assert.equal(3, db.notifications.size());
      });

  it('should show notification for "remove_relation"' +
      ' exceptions (service relations view)', function() {

        var view = new views.service_relations(
       { db: db,
         env: {
           remove_relation: function(id, newValues, callback) {
             callback(ERR_EV);
           }
         },
         getModelURL: NO_OP,
         container: viewContainer});

        db.relations.getById = function() {
          return {
            get: function(key) {
              if ('endpoints' === key) {
                return [
                  [{}, {name: ''}]
                ];
              }
              return null;
            }
          };
        };

        view.render();

        view.confirmRemoved({
          preventDefault: NO_OP,

          // This is a mock object of the relation button
          target: {
            ancestor: NO_OP,
            get: NO_OP
          }
        });
        view.remove_panel.footerNode.one('.btn-danger').simulate('click');
        view.remove_panel.destroy();

        assert.equal(1, db.notifications.size());
      });

  it('should show notification for "deploy" exceptions (charm view)',
      function() {
        var notified = false,
       db = {
         notifications: {
           add: function() {
             // This method should be called just once.
             assert.isFalse(notified);
             notified = true;
           }
         }
       },
       charm = {},
       container = {
         all: function() {
           return {each: NO_OP};
         },
         one: function() {
           return {get: NO_OP};
         }
       },
       env = {
         deploy: function(charmUrl, serviceName, config, callback) {
           callback(ERR_EV);
         }
       },
       mockView = {
         fire: NO_OP,
         _deployCallback: function() {
           // Executing the "views.charm.prototype._deployCallback"
           // function instead. The "views.charm.prototype._deployCallback"
           // is the one that will trigger the notification process.
           views.charm.prototype._deployCallback.apply(this, arguments);
         },
         get: function(key) {
           if ('charm' === key) {
             return charm;
           }
           if ('container' === key) {
             return container;
           }
           if ('db' === key) {
             return db;
           }
           if ('env' === key) {
             return env;
           }
           return null;
         }
       };

        views.charm.prototype.on_charm_deploy.apply(mockView, [ERR_EV]);
        assert.isTrue(notified);
      });

  it('should show errors for no unit, one unit and multiple ' +
      'units (service view)', function() {
        //_removeUnitCallback
        var mockView =
            { get: function(key) {
              return {
           getModelURL: NO_OP,
           db:
           { fire: NO_OP,
             notifications:
             { add: function(notification) {
               messages.push(notification.get('message'));
               titles.push(notification.get('title'));
             }}}}[key];
       }},
       messages = [],
       titles = [],
       baseView = new views.serviceBase({});

        baseView._removeUnitCallback.apply(mockView, [{
          err: true,
          unit_names: null
        }]);

        baseView._removeUnitCallback.apply(mockView, [{
          err: true,
          unit_names: []
        }]);

        baseView._removeUnitCallback.apply(mockView, [{
          err: true,
          unit_names: ['a']
        }]);

        baseView._removeUnitCallback.apply(mockView, [{
          err: true,
          unit_names: ['b', 'c']
        }]);

        function assertTrace(expected, trace) {
          assert.equal(expected.join(';'), trace.join(';'));
        }

        assertTrace(['Error removing unit', 'Error removing unit',
          'Error removing unit', 'Error removing units'], titles);
        assertTrace(['', '', 'Unit name: a', 'Unit names: b, c'], messages);
      });

});
<|endoftext|>


<commit_before>import * as clinicUtils from '../../../../app/core/clinicUtils';

/* global chai */
/* global sinon */
/* global describe */
/* global it */
/* global beforeEach */

const expect = chai.expect;

describe('clinicUtils', function() {
  it('should return all roles options', () => {
    expect(clinicUtils.roles).to.eql([
      { value: 'clinic_manager', label: 'Clinic Manager' },
      { value: 'diabetes_educator', label: 'Diabetes Educator' },
      { value: 'endocrinologist', label: 'Endocrinologist' },
      { value: 'front_desk', label: 'Front Desk' },
      { value: 'information_technology', label: 'IT/Technology' },
      { value: 'medical_assistant', label: 'Medical Assistant' },
      { value: 'nurse', label: 'Nurse/Nurse Practitioner' },
      { value: 'primary_care_physician', label: 'Primary Care Physician' },
      { value: 'physician_assistant', label: 'Physician Assistant' },
      { value: 'pharmacist', label: 'Pharmacist' },
      { value: 'health_student', label: 'Health Professions Student' },
      { value: 'other', label: 'Other' },
    ]);
  });

  it('should return all clinicTypes options', () => {
    expect(clinicUtils.clinicTypes).to.eql([
      { value: 'provider_practice', label: 'Provider Practice' },
      { value: 'healthcare_system', label: 'Healthcare System' },
      { value: 'other', label: 'Other' },
    ]);
  });

  it('should return all clinicSizes options', () => {
    expect(clinicUtils.clinicSizes).to.eql([
      { value: '0-249', label: '0-249' },
      { value: '250-499', label: '250-499' },
      { value: '500-999', label: '500-999' },
      { value: '1000+', label: '1000+' },
    ]);
  });

  describe('clinicValuesFromClinic', () => {
    it('should return default values for any missing clinic fields', () => {
      const emptyClinic = {};
      expect(clinicUtils.clinicValuesFromClinic(emptyClinic)).to.eql({
        name: '',
        address: '',
        city: '',
        state: '',
        postalCode: '',
        country: 'US',
        phoneNumbers: [
          {
            type: 'Office',
            number: '',
          },
        ],
        clinicType: '',
        clinicSize: '',
        website: '',
      });
    });

    it('should return existing fields values from the provided clinic', () => {
      const clinic = {
        name: 'Clinic 1',
        address: '253 MyStreet',
        city: 'MyTown',
        state: 'NB',
        postalCode: '12345',
        country: 'US',
        phoneNumbers: [
          {
            type: 'Office',
            number: '123-456-7890',
          },
        ],
        clinicType: 'provider_practice',
        clinicSize: '0-249',
        website: 'http://mysite.com',
      };

      expect(clinicUtils.clinicValuesFromClinic(clinic)).to.eql(clinic);
    });
  });

  describe('validationSchema', () => {
    it('should return a yup schema for clinic fields', () => {
      expect(clinicUtils.validationSchema).to.be.an('object');

      expect(clinicUtils.validationSchema._nodes).to.be.an('array').and.have.members([
        'name',
        'address',
        'city',
        'state',
        'postalCode',
        'country',
        'phoneNumbers',
        'clinicType',
        'clinicSize',
        'website',
      ]);

      expect(clinicUtils.validationSchema.fields.phoneNumbers.innerType._nodes).to.be.an('array').and.have.members([
        'type',
        'number',
      ]);
    });
  });
});
<commit_msg>[WEB-1260] Update tests<commit_after>import * as clinicUtils from '../../../../app/core/clinicUtils';

/* global chai */
/* global sinon */
/* global describe */
/* global it */
/* global beforeEach */

const expect = chai.expect;

describe('clinicUtils', function() {
  it('should return all roles options', () => {
    expect(clinicUtils.roles).to.eql([
      { value: 'clinic_manager', label: 'Clinic Manager' },
      { value: 'diabetes_educator', label: 'Diabetes Educator' },
      { value: 'endocrinologist', label: 'Endocrinologist' },
      { value: 'front_desk', label: 'Front Desk' },
      { value: 'information_technology', label: 'IT/Technology' },
      { value: 'medical_assistant', label: 'Medical Assistant' },
      { value: 'nurse', label: 'Nurse/Nurse Practitioner' },
      { value: 'primary_care_physician', label: 'Primary Care Physician' },
      { value: 'physician_assistant', label: 'Physician Assistant' },
      { value: 'pharmacist', label: 'Pharmacist' },
      { value: 'health_student', label: 'Health Professions Student' },
      { value: 'other', label: 'Other' },
    ]);
  });

  it('should return all clinicTypes options', () => {
    expect(clinicUtils.clinicTypes).to.eql([
      { value: 'provider_practice', label: 'Provider Practice' },
      { value: 'healthcare_system', label: 'Healthcare System' },
      { value: 'veterinary_clinic', label: 'Veterinary Clinic' },
      { value: 'other', label: 'Other' },
    ]);
  });

  it('should return all clinicSizes options', () => {
    expect(clinicUtils.clinicSizes).to.eql([
      { value: '0-249', label: '0-249' },
      { value: '250-499', label: '250-499' },
      { value: '500-999', label: '500-999' },
      { value: '1000+', label: '1000+' },
    ]);
  });

  describe('clinicValuesFromClinic', () => {
    it('should return default values for any missing clinic fields', () => {
      const emptyClinic = {};
      expect(clinicUtils.clinicValuesFromClinic(emptyClinic)).to.eql({
        name: '',
        address: '',
        city: '',
        state: '',
        postalCode: '',
        country: 'US',
        phoneNumbers: [
          {
            type: 'Office',
            number: '',
          },
        ],
        clinicType: '',
        clinicSize: '',
        website: '',
      });
    });

    it('should return existing fields values from the provided clinic', () => {
      const clinic = {
        name: 'Clinic 1',
        address: '253 MyStreet',
        city: 'MyTown',
        state: 'NB',
        postalCode: '12345',
        country: 'US',
        phoneNumbers: [
          {
            type: 'Office',
            number: '123-456-7890',
          },
        ],
        clinicType: 'provider_practice',
        clinicSize: '0-249',
        website: 'http://mysite.com',
      };

      expect(clinicUtils.clinicValuesFromClinic(clinic)).to.eql(clinic);
    });
  });

  describe('validationSchema', () => {
    it('should return a yup schema for clinic fields', () => {
      expect(clinicUtils.validationSchema).to.be.an('object');

      expect(clinicUtils.validationSchema._nodes).to.be.an('array').and.have.members([
        'name',
        'address',
        'city',
        'state',
        'postalCode',
        'country',
        'phoneNumbers',
        'clinicType',
        'clinicSize',
        'website',
      ]);

      expect(clinicUtils.validationSchema.fields.phoneNumbers.innerType._nodes).to.be.an('array').and.have.members([
        'type',
        'number',
      ]);
    });
  });
});
<|endoftext|>


<commit_before>(function() {

    var currentAttention = false;

    function drawAttention() {
        if (currentAttention == false) {
            currentAttention = true;
            chrome.app.window.current().drawAttention();
        }
    }

    function clearAttention() {
        if(currentAttention == true) {
            currentAttention = false;
            chrome.app.window.current().clearAttention();
        }
    }

    var webview = document.querySelector('webview');

    //Inject the notification trapper
    webview.addEventListener('contentload', function (e) {
        console.log('Starting poller');

        download("../guest/trap-notification.js", function(content){
            var code = 'var script = document.createElement("script");' +
                'script.innerHTML="eval(atob(\''+ btoa(content) + '\'))";' +
                'document.head.appendChild(script);';
            webview.executeScript(
                {
                    code: code
                },function(e){
                    console.log(chrome.runtime.lastError);
                }
            );
        });

        initTrapper();
        ensureNewMessagesAttention();

        //Hide the notification permission bar, in case something happens and we dont hide it
        webview.insertCSS({
            code: '.butterbar-notification {  display: none !important; }'
        });
    });

    //Workarounds to avoid the drawAttention being stuck
    window.addEventListener('focus', clearAttention);
    window.addEventListener('mousedown', clearAttention);
    window.addEventListener('keydown', clearAttention);

    function initTrapper() {
        //Initialize the notification handler. We will try to initialize every second until it replies
        var interval = setInterval(function () {
            webview.contentWindow.postMessage({type: 'handshake'}, "*");
        }, 1000);

        addEventListener('message', function(e) {
            var msg = e.data;
            if(msg.type == 'notif') {
                if (!document.hasFocus()) {
                    var notification = new Notification(msg.conversation, msg.data);

                    notification.addEventListener('click', function() {
                        webview.contentWindow.postMessage({type: 'click', id: msg.id}, "*");
                        clearAttention();
                        chrome.app.window.current().show(true);
                    });

                    setTimeout(function() {
                        notification.close();
                    }, 9000);

                    drawAttention();
                } else {
                    clearAttention();
                }
            } else if (msg.type == 'init') {
                clearInterval(interval);
                console.log("Notification trapper init");
            }
        });
    }

    function ensureNewMessagesAttention() {
        if(currentAttention) {
            setInterval(function () {
                webview.executeScript({
                    code: "document.querySelectorAll('.unread-count').length"
                }, function (r) {
                    var count = r[0];
                    if (count == 0) {
                        clearAttention();
                    }
                });
            }, 3000);
        }
    }

    function download(url, callback) {
        var oReq = new XMLHttpRequest();
        //oReq.responseType = 'arraybuffer';
        oReq.onload = function(){callback(oReq.response)};
        oReq.open("get", url, true);
        oReq.send();
    }

}());
<commit_msg>Clearing attention when the notification is closed<commit_after>(function() {

    var currentAttention = false;

    function drawAttention() {
        if (currentAttention == false) {
            currentAttention = true;
            chrome.app.window.current().drawAttention();
        }
    }

    function clearAttention() {
        if(currentAttention == true) {
            currentAttention = false;
            chrome.app.window.current().clearAttention();
        }
    }

    var webview = document.querySelector('webview');

    //Inject the notification trapper
    webview.addEventListener('contentload', function (e) {
        console.log('Starting poller');

        download("../guest/trap-notification.js", function(content){
            var code = 'var script = document.createElement("script");' +
                'script.innerHTML="eval(atob(\''+ btoa(content) + '\'))";' +
                'document.head.appendChild(script);';
            webview.executeScript(
                {
                    code: code
                },function(e){
                    console.log(chrome.runtime.lastError);
                }
            );
        });

        initTrapper();
        ensureNewMessagesAttention();

        //Hide the notification permission bar, in case something happens and we dont hide it
        webview.insertCSS({
            code: '.butterbar-notification {  display: none !important; }'
        });
    });

    //Workarounds to avoid the drawAttention being stuck
    window.addEventListener('focus', clearAttention);
    window.addEventListener('mousedown', clearAttention);
    window.addEventListener('keydown', clearAttention);

    function initTrapper() {
        //Initialize the notification handler. We will try to initialize every second until it replies
        var interval = setInterval(function () {
            webview.contentWindow.postMessage({type: 'handshake'}, "*");
        }, 1000);

        addEventListener('message', function(e) {
            var msg = e.data;
            if(msg.type == 'notif') {
                if (!document.hasFocus()) {
                    var notification = new Notification(msg.conversation, msg.data);

                    notification.addEventListener('click', function() {
                        webview.contentWindow.postMessage({type: 'click', id: msg.id}, "*");
                        clearAttention();
                        chrome.app.window.current().show(true);
                    });

                    notification.addEventListener('close', function() {
                        clearAttention();
                    });

                    setTimeout(function() {
                        notification.close();
                    }, 9000);

                    drawAttention();
                } else {
                    clearAttention();
                }
            } else if (msg.type == 'init') {
                clearInterval(interval);
                console.log("Notification trapper init");
            }
        });
    }

    function ensureNewMessagesAttention() {
        if(currentAttention) {
            setInterval(function () {
                webview.executeScript({
                    code: "document.querySelectorAll('.unread-count').length"
                }, function (r) {
                    var count = r[0];
                    if (count == 0) {
                        clearAttention();
                    }
                });
            }, 3000);
        }
    }

    function download(url, callback) {
        var oReq = new XMLHttpRequest();
        //oReq.responseType = 'arraybuffer';
        oReq.onload = function(){callback(oReq.response)};
        oReq.open("get", url, true);
        oReq.send();
    }

}());
<|endoftext|>


<commit_before>import React from 'react'
import { Form } from 'informed'
import renderer from 'react-test-renderer'
import { dark } from 'themes'
import { ThemeProvider } from 'styled-components'
import { Select } from 'components/UI'

describe('component.UI.Toggle', () => {
  it('should render correctly', () => {
    const selectItems = [
      { value: '- Please select -', key: '' },
      { value: 'Apple', key: 'apple' },
      { value: 'Pear', key: 'pear' },
      { value: 'Orange', key: 'orange' },
      { value: 'Grape', key: 'grape' },
      { value: 'Banana', key: 'banana' },
    ]
    const tree = renderer
      .create(
        <ThemeProvider theme={dark}>
          <Form>
            <Select field="name" items={selectItems} />
          </Form>
        </ThemeProvider>
      )
      .toJSON()
    expect(tree).toMatchSnapshot()
  })
})
<commit_msg>fix(test): update Select tests<commit_after>import React from 'react'
import { Form } from 'informed'
import renderer from 'react-test-renderer'
import { dark } from 'themes'
import { ThemeProvider } from 'styled-components'
import { Select } from 'components/UI'

import { IntlProvider } from 'react-intl'

describe('component.UI.Toggle', () => {
  it('should render correctly', () => {
    const selectItems = [
      { value: '- Please select -', key: '' },
      { value: 'Apple', key: 'apple' },
      { value: 'Pear', key: 'pear' },
      { value: 'Orange', key: 'orange' },
      { value: 'Grape', key: 'grape' },
      { value: 'Banana', key: 'banana' },
    ]
    const tree = renderer
      .create(
        <IntlProvider locale="en">
          <ThemeProvider theme={dark}>
            <Form>
              <Select field="name" items={selectItems} />
            </Form>
          </ThemeProvider>
        </IntlProvider>
      )
      .toJSON()
    expect(tree).toMatchSnapshot()
  })
})
<|endoftext|>


<commit_before>'use strict';

describe('timepicker', function () {
  var scope, $sandbox, $compile, $timeout, $strapConfig;

  beforeEach(module('$strap.directives'));

  beforeEach(inject(function ($injector, $rootScope, _$compile_, _$timeout_, _$strapConfig_) {
    scope = $rootScope;
    $compile = _$compile_;
    $timeout = _$timeout_;
  $strapConfig = _$strapConfig_;

    $sandbox = $('

').appendTo($('body'));
    scope.model = {};
  }));

  afterEach(function() {
    $sandbox.remove();
    scope.$destroy();
    $('.bootstrap-timepicker').remove();
  });

  var templates = {
    'default': '<input type="text" name="time" ng-model="model.time" data-default-time="false" data-show-meridian="false" bs-timepicker>',
    'addon': '<input type="text" name="time" ng-model="model.time" data-default-time="false" data-show-meridian="false" bs-timepicker>',
    'date': '<input type="text" name="time" ng-model="model.time" data-default-time="false" data-show-meridian="false" data-time-type="date" bs-timepicker>',
    'appendNoFocus': '
<input type="text" name="time" ng-model="model.time" data-default-time="false" data-show-meridian="false" data-time-type="date" bs-timepicker>
',
    'appendWithFocus': '
<input type="text" name="time" ng-model="model.time" data-default-time="false" data-show-meridian="false" data-time-type="date" open-on-focus="true" bs-timepicker>
'
  };

  function compileDirective(template) {
    template = template ? templates[template] : templates['default'];
    template = $(template).appendTo($sandbox);
    return $compile(template)(scope);
  }

  // Tests

  it('should add "data-toggle" attr for you', function () {
    var elm = compileDirective();
    expect(elm.attr('data-toggle')).toBe('timepicker');
  });

  it('should correctly call $.fn.timepicker', function () {
    var old = $.fn.timepicker;
    var spy = angular.extend(spyOn($.fn, 'timepicker'), old).andCallThrough();
    var elm = compileDirective();
    expect(spy).toHaveBeenCalled();
  });

  it('should show the timepicker on click', function() {
    var elm = compileDirective();
    elm.trigger('click');
    expect(elm.data('timepicker').$widget.hasClass('open')).toBe(true);
  });

  it('should show the timepicker on focus', function() {
    var elm = compileDirective();
    elm.trigger('focus');
    expect(elm.data('timepicker').$widget.hasClass('open')).toBe(true);
  });

  it('should show the timepicker on [data-toggle="timepicker"] click', function() {
    var elm = compileDirective('addon');
    elm.next('[data-toggle="timepicker"]').trigger('click');
    expect(elm.data('timepicker').$widget.hasClass('open')).toBe(true);
  });

  it('should correctly update both input value and bound model for string type', function() {
    var elm = compileDirective();
    elm.trigger('focus');
    elm.data('timepicker').$widget.find('a[data-action="incrementHour"]').trigger('click');
    $timeout.flush();
    expect(elm.val()).toBe('01:00');
    expect(scope.model.time).toBe('01:00');
  });

  it('should correctly update both input value and bound model for date type', function() {
    var elm = compileDirective('date');
    elm.trigger('focus');
    elm.data('timepicker').$widget.find('a[data-action="incrementHour"]').trigger('click');
    $timeout.flush();
    expect(elm.val()).toBe('01:00');
    expect(scope.model.time).toMatch(/(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{1,2} \d{4} 01:00:\d{2} GMT-\d{4} \([A-Z]{3}\)/);
  });

  it('should not accept bad input', function() {
    var elm = compileDirective();
    elm.trigger('click');
    elm.val('bad');
    elm.trigger('blur');
    expect(elm.val()).toBe('00:00');
  });

  it('should not show widget on focus when inside input-append if openOnFocus is set to false', function() {
    var elm = compileDirective('appendNoFocus');
    var inputElm = $(elm.children('input')[0]);
    inputElm.trigger('focus');
    expect(inputElm.data('timepicker').$widget.hasClass('open')).toBe(false);
  });

  it('should show widget on focus when inside input-append if openOnFocus is set', function() {
    var elm = compileDirective('appendWithFocus');
    var inputElm = $(elm.children('input')[0]);
    inputElm.trigger('focus');
    expect(inputElm.data('timepicker').$widget.hasClass('open')).toBe(true);
  });
});
<commit_msg>chore(tests): Fixed a test case for timepicker.<commit_after>'use strict';

describe('timepicker', function () {
  var scope, $sandbox, $compile, $timeout, $strapConfig;

  beforeEach(module('$strap.directives'));

  beforeEach(inject(function ($injector, $rootScope, _$compile_, _$timeout_, _$strapConfig_) {
    scope = $rootScope;
    $compile = _$compile_;
    $timeout = _$timeout_;
  $strapConfig = _$strapConfig_;

    $sandbox = $('

').appendTo($('body'));
    scope.model = {};
  }));

  afterEach(function() {
    $sandbox.remove();
    scope.$destroy();
    $('.bootstrap-timepicker').remove();
  });

  var templates = {
    'default': '<input type="text" name="time" ng-model="model.time" data-default-time="false" data-show-meridian="false" bs-timepicker>',
    'addon': '<input type="text" name="time" ng-model="model.time" data-default-time="false" data-show-meridian="false" bs-timepicker>',
    'date': '<input type="text" name="time" ng-model="model.time" data-default-time="false" data-show-meridian="false" data-time-type="date" bs-timepicker>',
    'appendNoFocus': '
<input type="text" name="time" ng-model="model.time" data-default-time="false" data-show-meridian="false" data-time-type="date" bs-timepicker>
',
    'appendWithFocus': '
<input type="text" name="time" ng-model="model.time" data-default-time="false" data-show-meridian="false" data-time-type="date" open-on-focus="true" bs-timepicker>
'
  };

  function compileDirective(template) {
    template = template ? templates[template] : templates['default'];
    template = $(template).appendTo($sandbox);
    return $compile(template)(scope);
  }

  // Tests

  it('should add "data-toggle" attr for you', function () {
    var elm = compileDirective();
    expect(elm.attr('data-toggle')).toBe('timepicker');
  });

  it('should correctly call $.fn.timepicker', function () {
    var old = $.fn.timepicker;
    var spy = angular.extend(spyOn($.fn, 'timepicker'), old).andCallThrough();
    var elm = compileDirective();
    expect(spy).toHaveBeenCalled();
  });

  it('should show the timepicker on click', function() {
    var elm = compileDirective();
    elm.trigger('click');
    expect(elm.data('timepicker').$widget.hasClass('open')).toBe(true);
  });

  it('should show the timepicker on focus', function() {
    var elm = compileDirective();
    elm.trigger('focus');
    expect(elm.data('timepicker').$widget.hasClass('open')).toBe(true);
  });

  it('should show the timepicker on [data-toggle="timepicker"] click', function() {
    var elm = compileDirective('addon');
    elm.next('[data-toggle="timepicker"]').trigger('click');
    expect(elm.data('timepicker').$widget.hasClass('open')).toBe(true);
  });

  it('should correctly update both input value and bound model for string type', function() {
    var elm = compileDirective();
    elm.trigger('focus');
    elm.data('timepicker').$widget.find('a[data-action="incrementHour"]').trigger('click');
    $timeout.flush();
    expect(elm.val()).toBe('01:00');
    expect(scope.model.time).toBe('01:00');
  });

  it('should correctly update both input value and bound model for date type', function() {
    var elm = compileDirective('date');
    elm.trigger('focus');
    elm.data('timepicker').$widget.find('a[data-action="incrementHour"]').trigger('click');
    $timeout.flush();
    expect(elm.val()).toBe('01:00');
    expect(scope.model.time).toMatch(/(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{1,2} \d{4} 01:00:\d{2} GMT[-+]\d{4} \([A-Z]{3}\)/);
  });

  it('should not accept bad input', function() {
    var elm = compileDirective();
    elm.trigger('click');
    elm.val('bad');
    elm.trigger('blur');
    expect(elm.val()).toBe('00:00');
  });

  it('should not show widget on focus when inside input-append if openOnFocus is set to false', function() {
    var elm = compileDirective('appendNoFocus');
    var inputElm = $(elm.children('input')[0]);
    inputElm.trigger('focus');
    expect(inputElm.data('timepicker').$widget.hasClass('open')).toBe(false);
  });

  it('should show widget on focus when inside input-append if openOnFocus is set', function() {
    var elm = compileDirective('appendWithFocus');
    var inputElm = $(elm.children('input')[0]);
    inputElm.trigger('focus');
    expect(inputElm.data('timepicker').$widget.hasClass('open')).toBe(true);
  });
});
<|endoftext|>


<commit_before>import R from 'ramda';
import * as ActionType from '../actionTypes';

export const meta = (state, action) => {
  switch (action.type) {
    case ActionType.META_UPDATE: {
      return R.merge(state, action.payload);
    }
    default:
      return state;
  }
};
<commit_msg>fix(reducers): add default state = {}<commit_after>import R from 'ramda';
import * as ActionType from '../actionTypes';

export const meta = (state = {}, action) => {
  switch (action.type) {
    case ActionType.META_UPDATE: {
      return R.merge(state, action.payload);
    }
    default:
      return state;
  }
};
<|endoftext|>


<commit_before>import _ from 'lodash';
import { USER_PLAYLIST_CONSTANTS, PLAYLIST_TRACKS_CONSTANTS } from '../actions/user';

const initialState = {
  playlists: [],
  totalCount: null,
  pendingCount: null,
  isFetching: false,
  error: null
};

export default function playlists(state = initialState, action) {
  switch (action.type) {
    case USER_PLAYLIST_CONSTANTS.PENDING:
      return Object.assign({}, state, {
        isFetching: true,
        error: null
      });
    case USER_PLAYLIST_CONSTANTS.SUCCESS:
      let data = action.data;
      let newPlaylists = _.map(data.items, (playlistData) => {
        return {
          id: playlistData.id,
          name: playlistData.name,
          userId: playlistData.owner.id,
          totalTracksCount: playlistData.tracks.total,
          tracks: [],
          isPublic: playlistData.public
        }
      });
      let updatedPlaylists = _.concat(state.playlists, newPlaylists);
      let totalPlaylists = data.total;
      return Object.assign({}, state, {
        totalCount: totalPlaylists,
        pendingCount: totalPlaylists - updatedPlaylists.length,
        playlists: updatedPlaylists,
        isFetching: false,
        error: null
      });
    case USER_PLAYLIST_CONSTANTS.FAILURE:
      return Object.assign({}, state, {
        isFetching: false,
        error: action.error
      });
    case PLAYLIST_TRACKS_CONSTANTS.PENDING:
      return Object.assign({}, state, {
        isFetching: true,
        error: null
      });
    case PLAYLIST_TRACKS_CONSTANTS.SUCCESS:
      let tracks = _.map(action.data.items, (item) => {
        let track = item.track;
        return {
          name: track.name,
          album: track.album.name,
          artists: _.map(track.artists, (artist) => artist.name)
        }
      });
      let updatedPlaylists = _.cloneDeep(state.playlists);
      let index = _.findIndex(updatedPlaylists, (playlist) => playlist.id == action.data.playlistId);
      let playlist = updatedPlaylists[index];
      playlist.tracks = _.concat(playlist.tracks, tracks);
      return Object.assign({}, state, {
        playlists: updatedPlaylists,
        isFetching: false,
        error: null
      });
    case PLAYLIST_TRACKS_CONSTANTS.FAILURE:
      return Object.assign({}, state, {
        isFetching: false,
        error: action.error
      });
    default:
      return state;
  }
}
<commit_msg>Refactor: Extract into  methods.<commit_after>import _ from 'lodash';
import { USER_PLAYLIST_CONSTANTS, PLAYLIST_TRACKS_CONSTANTS } from '../actions/user';

const initialState = {
  playlists: [],
  totalCount: null,
  pendingCount: null,
  isFetching: false,
  error: null
};

function playlistTracksSucccess(state, action){
  let tracks = _.map(action.data.items, (item) => {
    let track = item.track;
    return {
      name: track.name,
      album: track.album.name,
      artists: _.map(track.artists, (artist) => artist.name)
    }
  });
  let updatedPlaylists = _.cloneDeep(state.playlists);
  let index = _.findIndex(updatedPlaylists, (playlist) => playlist.id == action.data.playlistId);
  let playlist = updatedPlaylists[index];
  playlist.tracks = _.concat(playlist.tracks, tracks);
  return Object.assign({}, state, {
    playlists: updatedPlaylists,
    isFetching: false,
    error: null
  });
}

function userPlaylistsSuccess(state, action){
  let data = action.data;
  let newPlaylists = _.map(data.items, (playlistData) => {
    return {
      id: playlistData.id,
      name: playlistData.name,
      userId: playlistData.owner.id,
      totalTracksCount: playlistData.tracks.total,
      tracks: [],
      isPublic: playlistData.public
    }
  });
  let updatedPlaylists = _.concat(state.playlists, newPlaylists);
  let totalPlaylists = data.total;
  return Object.assign({}, state, {
    totalCount: totalPlaylists,
    pendingCount: totalPlaylists - updatedPlaylists.length,
    playlists: updatedPlaylists,
    isFetching: false,
    error: null
  });
}

export default function playlists(state = initialState, action) {
  switch (action.type) {
    case USER_PLAYLIST_CONSTANTS.PENDING:
      return Object.assign({}, state, {
        isFetching: true,
        error: null
      });
    case USER_PLAYLIST_CONSTANTS.SUCCESS:
      return userPlaylistsSuccess(state, action);
    case USER_PLAYLIST_CONSTANTS.FAILURE:
      return Object.assign({}, state, {
        isFetching: false,
        error: action.error
      });
    case PLAYLIST_TRACKS_CONSTANTS.PENDING:
      return Object.assign({}, state, {
        isFetching: true,
        error: null
      });
    case PLAYLIST_TRACKS_CONSTANTS.SUCCESS:
      return playlistTracksSucccess(state, action);
    case PLAYLIST_TRACKS_CONSTANTS.FAILURE:
      return Object.assign({}, state, {
        isFetching: false,
        error: action.error
      });
    default:
      return state;
  }
}
<|endoftext|>


<commit_before>const log = require('winston')
const donation = require('../database/donation')
const spending = require('../database/spending')
const db = require('../database')

const covered = (queued, spent, amount) => {
  if(!queued.length) {
    const error = new Error()
    error.name = 'overspending'
    throw error
  }
  if(amount <= 0) return spent

  const [head, ...tail] = queued
  const s = spent.concat(head)
  const a = amount - head.amount
  return covered(tail, s, a)
}

module.exports = (s) => {
  log.debug('Spending detected')
  console.log(s)
  const amount = s.amount
  let spent_ids

  return donation.queue()
  .then(queued => {
    const spent = covered(queued, [], amount)
    .map(el => {
      el.state = 'spent'
      return el
    })
    spent_ids = spent.map(el => el._id)
    return db.bulk(spent)
  })
  .then(() => {
    s.donations = spent_ids
    return spending.create(s)
  })
  .then(() => {
    return spent_ids
  })
}
<commit_msg>Include email in spening donations<commit_after>const log = require('winston')
const donation = require('../database/donation')
const spending = require('../database/spending')
const db = require('../database')

const covered = (queued, spent, amount) => {
  if(!queued.length) {
    const error = new Error()
    error.name = 'overspending'
    throw error
  }
  if(amount <= 0) return spent

  const [head, ...tail] = queued
  const s = spent.concat(head)
  const a = amount - head.amount
  return covered(tail, s, a)
}

module.exports = (s) => {
  log.debug('Spending detected')
  console.log(s)
  const amount = s.amount
  let spent_ids

  return donation.queue()
  .then(queued => {
    const spent = covered(queued, [], amount)
    .map(el => {
      el.state = 'spent'
      return el
    })
    spent_ids = spent.map(el => ({
      id: el._id,
      email: el.email
    }))
    return db.bulk(spent)
  })
  .then(() => {
    s.donations = spent_ids
    return spending.create(s)
  })
  .then(() => {
    return spent_ids
  })
}
<|endoftext|>


<commit_before>/**
 * Copyright 2015, Yahoo! Inc.
 * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */

import Ember from 'ember';
import Locale from 'ember-intl/models/locale';
import createFormatCache from 'ember-intl/format-cache/memoizer';
import { IntlRelativeFormat, IntlMessageFormat } from 'ember-intl/utils/data';

var makeArray = Ember.makeArray;
var get       = Ember.get;

function assertIsDate (date, errMsg) {
    Ember.assert(errMsg, isFinite(date));
}

function getLocaleInstance (locale) {
    if (locale instanceof Locale) {
        return locale;
    };

    if (typeof locale === 'string') {
        return this.container.lookup('locale:' + localeId.toLowerCase());
    }

    throw new Error('`locale` must be a string or a locale instance');
}

export default Ember.Controller.extend(Ember.Evented, {
    locales:           null,
    defaultLocale:     null,

    getDateTimeFormat: null,
    getRelativeFormat: null,
    getMessageFormat:  null,
    getNumberFormat:   null,

    setupMemoizers: Ember.on('init', function () {
        this.setProperties({
            getDateTimeFormat: createFormatCache(Intl.DateTimeFormat),
            getRelativeFormat: createFormatCache(IntlRelativeFormat),
            getNumberFormat:   createFormatCache(Intl.NumberFormat),
            getMessageFormat:  createFormatCache(IntlMessageFormat)
        });
    }),

    current: Ember.computed('locales', 'defaultLocale', function () {
        var locales       = makeArray(get(this, 'locales'));
        var defaultLocale = get(this, 'defaultLocale');

        if (Ember.isPresent(defaultLocale) && locales.indexOf(defaultLocale) === -1) {
            locales.push(defaultLocale);
        }

        return locales;
    }).readOnly(),

    formats: Ember.computed(function () {
        return this.container.lookup('formats:main', {
            instantiate: false
        }) || {};
    }).readOnly(),

    localeChanged: Ember.observer('current', function () {
        Ember.run.once(this, this.notifyLocaleChanged);
    }),

    addMessage: function (locale, key, value) {
        locale = getLocaleInstance.call(this, locale);

        return locale.addMessage(key, value);
    },

    addMessages: function (locale, messageObject) {
        locale = getLocaleInstance.call(this, locale);

        return locale.addMessages(messageObject);
    },

    notifyLocaleChanged: function () {
        this.trigger('localesChanged');
    },

    formatRelative: function (date, options) {
        date = new Date(date);
        assertIsDate(date, 'A date or timestamp must be provided to formatRelative()');

        return this._format('relative', date, options);
    },

    formatMessage: function (message, values, options) {
        // When `message` is a function, assume it's an IntlMessageFormat
        // instance's `format()` method passed by reference, and call it. This
        // is possible because its `this` will be pre-bound to the instance.
        if (typeof message === 'function') {
            return message(values);
        }

        options = options || {};

        var locales = makeArray(options.locales);
        var formats = options.formats || get(this, 'formats');

        if (Ember.isEmpty(locales)) {
            locales = get(this, 'current');
        }

        if (typeof message === 'string') {
            message = this.getMessageFormat(message, locales, formats);
        }

        return message.format(values);
    },

    formatTime: function (date, options) {
        date = new Date(date);
        assertIsDate(date, 'A date or timestamp must be provided to formatTime()');

        return this._format('time', date, options);
    },

    formatDate: function (date, options) {
        date = new Date(date);
        assertIsDate(date, 'A date or timestamp must be provided to formatDate()');

        return this._format('date', date, options);
    },

    formatNumber: function (num, options) {
        return this._format('number', num, options);
    },

    _format: function (type, value, options) {
        options = options || {};

        var locales = makeArray(options.locales);
        var formats = get(this, 'formats');

        if (Ember.isEmpty(locales)) {
            locales = get(this, 'current');
        }

        if (typeof options.formats === 'string') {
            options = get(this, 'formats.' + type + '.' + options.formats);
        } else if (typeof options.formats === 'object') {
            options = options.formats;
        }

        if (typeof options === 'string') {
            try {
                options = formats[type][options];
            } catch (e) {
                options = undefined;
            } finally {
                if (options === undefined) {
                    throw new ReferenceError('No ' + type + ' format named: ' + options);
                }
            }
        }

        switch (type) {
            case 'date':
            case 'time':
                return this.getDateTimeFormat(locales, options).format(value);
            case 'number':
                return this.getNumberFormat(locales, options).format(value);
            case 'relative':
                return this.getRelativeFormat(locales, options).format(value);
            default:
                throw new Error('Unrecognized simple format type: ' + type);
        }
    }
});
<commit_msg>Use Ember.Service instead of Ember.Controller<commit_after>/**
 * Copyright 2015, Yahoo! Inc.
 * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */

import Ember from 'ember';
import Locale from 'ember-intl/models/locale';
import createFormatCache from 'ember-intl/format-cache/memoizer';
import { IntlRelativeFormat, IntlMessageFormat } from 'ember-intl/utils/data';

var makeArray = Ember.makeArray;
var get       = Ember.get;

function assertIsDate (date, errMsg) {
    Ember.assert(errMsg, isFinite(date));
}

function getLocaleInstance (locale) {
    if (locale instanceof Locale) {
        return locale;
    };

    if (typeof locale === 'string') {
        return this.container.lookup('locale:' + localeId.toLowerCase());
    }

    throw new Error('`locale` must be a string or a locale instance');
}

export default Ember.Service.extend(Ember.Evented, {
    locales:           null,
    defaultLocale:     null,

    getDateTimeFormat: null,
    getRelativeFormat: null,
    getMessageFormat:  null,
    getNumberFormat:   null,

    setupMemoizers: Ember.on('init', function () {
        this.setProperties({
            getDateTimeFormat: createFormatCache(Intl.DateTimeFormat),
            getRelativeFormat: createFormatCache(IntlRelativeFormat),
            getNumberFormat:   createFormatCache(Intl.NumberFormat),
            getMessageFormat:  createFormatCache(IntlMessageFormat)
        });
    }),

    current: Ember.computed('locales', 'defaultLocale', function () {
        var locales       = makeArray(get(this, 'locales'));
        var defaultLocale = get(this, 'defaultLocale');

        if (Ember.isPresent(defaultLocale) && locales.indexOf(defaultLocale) === -1) {
            locales.push(defaultLocale);
        }

        return locales;
    }).readOnly(),

    formats: Ember.computed(function () {
        return this.container.lookup('formats:main', {
            instantiate: false
        }) || {};
    }).readOnly(),

    localeChanged: Ember.observer('current', function () {
        Ember.run.once(this, this.notifyLocaleChanged);
    }),

    addMessage: function (locale, key, value) {
        locale = getLocaleInstance.call(this, locale);

        return locale.addMessage(key, value);
    },

    addMessages: function (locale, messageObject) {
        locale = getLocaleInstance.call(this, locale);

        return locale.addMessages(messageObject);
    },

    notifyLocaleChanged: function () {
        this.trigger('localesChanged');
    },

    formatRelative: function (date, options) {
        date = new Date(date);
        assertIsDate(date, 'A date or timestamp must be provided to formatRelative()');

        return this._format('relative', date, options);
    },

    formatMessage: function (message, values, options) {
        // When `message` is a function, assume it's an IntlMessageFormat
        // instance's `format()` method passed by reference, and call it. This
        // is possible because its `this` will be pre-bound to the instance.
        if (typeof message === 'function') {
            return message(values);
        }

        options = options || {};

        var locales = makeArray(options.locales);
        var formats = options.formats || get(this, 'formats');

        if (Ember.isEmpty(locales)) {
            locales = get(this, 'current');
        }

        if (typeof message === 'string') {
            message = this.getMessageFormat(message, locales, formats);
        }

        return message.format(values);
    },

    formatTime: function (date, options) {
        date = new Date(date);
        assertIsDate(date, 'A date or timestamp must be provided to formatTime()');

        return this._format('time', date, options);
    },

    formatDate: function (date, options) {
        date = new Date(date);
        assertIsDate(date, 'A date or timestamp must be provided to formatDate()');

        return this._format('date', date, options);
    },

    formatNumber: function (num, options) {
        return this._format('number', num, options);
    },

    _format: function (type, value, options) {
        options = options || {};

        var locales = makeArray(options.locales);
        var formats = get(this, 'formats');

        if (Ember.isEmpty(locales)) {
            locales = get(this, 'current');
        }

        if (typeof options.formats === 'string') {
            options = get(this, 'formats.' + type + '.' + options.formats);
        } else if (typeof options.formats === 'object') {
            options = options.formats;
        }

        if (typeof options === 'string') {
            try {
                options = formats[type][options];
            } catch (e) {
                options = undefined;
            } finally {
                if (options === undefined) {
                    throw new ReferenceError('No ' + type + ' format named: ' + options);
                }
            }
        }

        switch (type) {
            case 'date':
            case 'time':
                return this.getDateTimeFormat(locales, options).format(value);
            case 'number':
                return this.getNumberFormat(locales, options).format(value);
            case 'relative':
                return this.getRelativeFormat(locales, options).format(value);
            default:
                throw new Error('Unrecognized simple format type: ' + type);
        }
    }
});
<|endoftext|>


<commit_before>// Mist textures
const textures = [
  require('./textures/mist-particle-1.png'),
  require('./textures/mist-particle-2.png'),
  require('./textures/mist-particle-3.png'),
  require('./textures/mist-particle-4.png'),
  require('./textures/mist-particle-5.png'),
];

// Helper functions

// My [].fill polyfill
if (!Array.prototype.fill) {
  /* eslint-disable no-extend-native */
  Array.prototype.fill = (value) => {
    for (let i = 0; i < this.length; i += 1) {
      this[i] = value;
    }
    return this;
  };
  /* eslint-enable no-extend-native */
}

/** Return a random number between `low` and `high` */
function random(low, high) {
  return (Math.random() * (high - low)) + low;
}

/** Return a random integer between `low` and `high-1` */
function randint(low, high) {
  return Math.floor(random(low, high));
}

/** Return a random item from an array */
function randchoice(array) {
  return array[randint(0, array.length)];
}

/** Implements basic particle physics (moving and bouncing) */
class Particle {
  /**
   * Create a new particle in a simulation.
   * Particles have positions and velocities, and remember which renderer they're bound to.
   * @param {ParticleRenderer} renderer - the ParticleRender that the particle belongs to.
   * @param {number} x - the initial X position of the particle
   * @param {number} y - the initial Y position of the particle
   * @param {number} vx - the initial X velocity of the particle
   * @param {number} vy - the initial Y velocity of the particle
   */
  constructor(renderer, x, y, vx, vy, image) {
    this.renderer = renderer;
    // Path to particle texture. Not used by Particle, used by ParticleRenderer
    this.image = image;

    this.x = x;    // X position on canvas
    this.y = y;    // Y position on canvas
    this.vx = vx;  // X velocity
    this.vy = vy;  // Y velocity
  }

  /** Advance the simulation by one step */
  step() {
    // Bounce particles when they hit the edges of the canvas
    if (this.x < 0 || this.x >= this.renderer.width()) {
      this.bounceX();
    }
    if (this.y < 0 || this.y >= this.renderer.height()) {
      this.bounceY();
    }

    this.x += this.vx;
    this.y += this.vy;
  }

  /** Cause the current particle to bounce in the X direction */
  bounceX() {
    this.vx = -1 * this.vx;
  }

  /** Cause the current particle to bounce in the Y direction */
  bounceY() {
    this.vy = -1 * this.vy;
  }
}

/** Orchestrates and renders particles */
class ParticleRenderer {
  /**
   * Create a new particle renderer.
   * @param {CanvasRenderingContext2D} ctx - the rendering context of the canvas to draw on
   * @param {number} particleCount - the number of particles to maintain in the simulation
   */
  constructor(ctx, particleCount) {
    this.ctx = ctx;
    this.particleCount = particleCount;

    this.particles = new Array(this.particleCount).fill(0).map(() => new Particle(
      this,
      randint(0, this.width()),   // X position
      randint(0, this.height()),  // Y position
      randint(0, 5),              // X velocity
      randint(0, 5),              // Y velocity
      randchoice(textures),
    ));
  }

  /**
   * Draw the particles on the canvas
   */
  draw() {
    // TODO
    this.particles.forEach(() => {});
  }

  /**
   * Advance the simulation by one step
   */
  step() {
    this.particles.forEach(particle => particle.step());
  }

  /**
   * Begin a render loop
   */
  start() {
    // TODO
    this.interval = setInterval(() => {
      this.step();
      requestAnimationFrame(this.draw);
    }, 100);
  }

  /**
   * Get the width of the canvas coordinate system.
   * @return {number} the width of the canvas
   */
  width() {
    return this.ctx.canvas.width;
  }

  /**
   * Get the height of the canvas coordinate system
   * @return {number} the height of the canvas
   */
  height() {
    return this.ctx.canvas.height;
  }
}

window.addEventListener('resize', () => {
  const canvas = document.getElementById('mist');
  const ctx = canvas.getContext('2d');

  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight * 0.8;

  ctx.fillStyle = 'white';
  ctx.font = `${canvas.height}px Arial`;
  ctx.fillText('Hi', 10, canvas.height);

  // Make everything faded with a gradient

  ctx.globalCompositeOperation = 'destination-in';

  const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
  gradient.addColorStop(0, 'rgba(255, 255, 255, 0)');
  gradient.addColorStop(1, 'rgba(255, 255, 255, 1)');
  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, canvas.width, canvas.height);
});

window.addEventListener('load', () => window.dispatchEvent(new Event('resize')));

window.addEventListener('load', () => {
  const canvas = document.getElementById('mist');
  const ctx = canvas.getContext('2d');
  window.particleSim = new ParticleRenderer(ctx, 10);
});
<commit_msg>Rename global simulation<commit_after>// Mist textures
const textures = [
  require('./textures/mist-particle-1.png'),
  require('./textures/mist-particle-2.png'),
  require('./textures/mist-particle-3.png'),
  require('./textures/mist-particle-4.png'),
  require('./textures/mist-particle-5.png'),
];

// Helper functions

// My [].fill polyfill
if (!Array.prototype.fill) {
  /* eslint-disable no-extend-native */
  Array.prototype.fill = (value) => {
    for (let i = 0; i < this.length; i += 1) {
      this[i] = value;
    }
    return this;
  };
  /* eslint-enable no-extend-native */
}

/** Return a random number between `low` and `high` */
function random(low, high) {
  return (Math.random() * (high - low)) + low;
}

/** Return a random integer between `low` and `high-1` */
function randint(low, high) {
  return Math.floor(random(low, high));
}

/** Return a random item from an array */
function randchoice(array) {
  return array[randint(0, array.length)];
}

/** Implements basic particle physics (moving and bouncing) */
class Particle {
  /**
   * Create a new particle in a simulation.
   * Particles have positions and velocities, and remember which renderer they're bound to.
   * @param {ParticleRenderer} renderer - the ParticleRender that the particle belongs to.
   * @param {number} x - the initial X position of the particle
   * @param {number} y - the initial Y position of the particle
   * @param {number} vx - the initial X velocity of the particle
   * @param {number} vy - the initial Y velocity of the particle
   */
  constructor(renderer, x, y, vx, vy, image) {
    this.renderer = renderer;
    // Path to particle texture. Not used by Particle, used by ParticleRenderer
    this.image = image;

    this.x = x;    // X position on canvas
    this.y = y;    // Y position on canvas
    this.vx = vx;  // X velocity
    this.vy = vy;  // Y velocity
  }

  /** Advance the simulation by one step */
  step() {
    // Bounce particles when they hit the edges of the canvas
    if (this.x < 0 || this.x >= this.renderer.width()) {
      this.bounceX();
    }
    if (this.y < 0 || this.y >= this.renderer.height()) {
      this.bounceY();
    }

    this.x += this.vx;
    this.y += this.vy;
  }

  /** Cause the current particle to bounce in the X direction */
  bounceX() {
    this.vx = -1 * this.vx;
  }

  /** Cause the current particle to bounce in the Y direction */
  bounceY() {
    this.vy = -1 * this.vy;
  }
}

/** Orchestrates and renders particles */
class ParticleRenderer {
  /**
   * Create a new particle renderer.
   * @param {CanvasRenderingContext2D} ctx - the rendering context of the canvas to draw on
   * @param {number} particleCount - the number of particles to maintain in the simulation
   */
  constructor(ctx, particleCount) {
    this.ctx = ctx;
    this.particleCount = particleCount;

    this.particles = new Array(this.particleCount).fill(0).map(() => new Particle(
      this,
      randint(0, this.width()),   // X position
      randint(0, this.height()),  // Y position
      randint(0, 5),              // X velocity
      randint(0, 5),              // Y velocity
      randchoice(textures),
    ));
  }

  /**
   * Draw the particles on the canvas
   */
  draw() {
    // TODO
    this.particles.forEach(() => {});
  }

  /**
   * Advance the simulation by one step
   */
  step() {
    this.particles.forEach(particle => particle.step());
  }

  /**
   * Begin a render loop
   */
  start() {
    // TODO
    this.interval = setInterval(() => {
      this.step();
      requestAnimationFrame(this.draw);
    }, 100);
  }

  /**
   * Get the width of the canvas coordinate system.
   * @return {number} the width of the canvas
   */
  width() {
    return this.ctx.canvas.width;
  }

  /**
   * Get the height of the canvas coordinate system
   * @return {number} the height of the canvas
   */
  height() {
    return this.ctx.canvas.height;
  }
}

window.addEventListener('resize', () => {
  const canvas = document.getElementById('mist');
  const ctx = canvas.getContext('2d');

  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight * 0.8;

  ctx.fillStyle = 'white';
  ctx.font = `${canvas.height}px Arial`;
  ctx.fillText('Hi', 10, canvas.height);

  // Make everything faded with a gradient

  ctx.globalCompositeOperation = 'destination-in';

  const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
  gradient.addColorStop(0, 'rgba(255, 255, 255, 0)');
  gradient.addColorStop(1, 'rgba(255, 255, 255, 1)');
  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, canvas.width, canvas.height);
});

window.addEventListener('load', () => window.dispatchEvent(new Event('resize')));

window.addEventListener('load', () => {
  const canvas = document.getElementById('mist');
  const ctx = canvas.getContext('2d');
  window.smokeSim = new ParticleRenderer(ctx, 10);
});
<|endoftext|>


<commit_before>AccountsTemplates.init();

Tinytest.add("AccountsTemplates - addField/removeField", function(test) {
    // Calls after AccountsTemplates.init()
    AccountsTemplates._initialized = true;
    test.throws(function() {
        AccountsTemplates.addField('');
    }, function(err) {
        if (err instanceof Error && err.message === 'AccountsTemplates.addField should strictly be called before AccountsTemplates.init!')
            return true;
    });
    test.throws(function() {
        AccountsTemplates.removeField('');
    }, function(err) {
        if (err instanceof Error && err.message === 'AccountsTemplates.removeField should strictly be called before AccountsTemplates.init!')
            return true;
    });
    AccountsTemplates._initialized = false;

    // Trying to remove a non-existing field
    test.throws(function() {
        AccountsTemplates.removeField('foo');
    }, function(err) {
        if (err instanceof Error && err.message == 'A field called foo does not exist!')
            return true;
    });

    // Trying to remove an existing field
    AccountsTemplates.removeField('login');
    test.isUndefined(AccountsTemplates.getField('login'));

    // Trying to add an already existing field
    test.throws(function() {
        AccountsTemplates.addField(AccountsTemplates.getField('password'));
    }, function(err) {
        if (err instanceof Error && err.message == 'A field called password already exists!')
            return true;
    });

    var login = {
        name: 'login',
        displayName: 'Email',
        type: 'email'
    };

    // Invalid field properties
    test.throws(function() {
        AccountsTemplates.addField(_.extend(_.clone(login), {
            foo: 'bar'
        }));
    }, Error);

    // Successful add
    AccountsTemplates.addField(login);

    // Invalid field.type
    test.throws(function() {
        AccountsTemplates.addField({
            name: 'foo',
            displayName: 'Foo',
            type: 'bar'
        });
    }, function(err) {
        if (err instanceof Error && err.message == 'field.type is not valid!')
            return true;
    });

    // Invalid minLength
    test.throws(function() {
        AccountsTemplates.addField({
            name: 'first-name',
            displayName: 'First Name',
            type: 'text',
            minLength: 0
        });
    }, function(err) {
        if (err instanceof Error && err.message == 'field.minLength should be greater than zero!')
            return true;
    });
    // Invalid maxLength
    test.throws(function() {
        AccountsTemplates.addField({
            name: 'first-name',
            displayName: 'First Name',
            type: 'text',
            maxLength: 0
        });
    }, function(err) {
        if (err instanceof Error && err.message == 'field.maxLength should be greater than zero!')
            return true;
    });
    // maxLength < minLength
    test.throws(function() {
        AccountsTemplates.addField({
            name: 'first-name',
            displayName: 'First Name',
            type: 'text',
            minLength: 2,
            maxLength: 1
        });
    }, function(err) {
        if (err instanceof Error && err.message == 'field.maxLength should be greater than field.maxLength!')
            return true;
    });

    // Successful add
    var first_name = {
        name: 'first_name',
        displayName: 'First Name',
        type: 'text',
        minLength: 2,
        maxLength: 50,
        required: true
    };
    AccountsTemplates.addField(first_name);
    test.equal(AccountsTemplates.getField('first_name'), first_name);
    // Now removes ot to be consistend with tests re-run
    AccountsTemplates.removeField('first_name');
});

Tinytest.add("AccountsTemplates - addFields", function(test) {
    // Fake uninitialized state...
    AccountsTemplates._initialized = false;

    if (Meteor.isClient) {
        // addFields does not exist client-side
        test.throws(function() {
            AccountsTemplates.addFields();
        });
    } else {
        // Not an array of objects
        test.throws(function() {
            AccountsTemplates.addFields('');
        }, function(err) {
            if (err instanceof Error && err.message === 'field argument should be an array of valid field objects!')
                return true;
        });
        test.throws(function() {
            AccountsTemplates.addFields(100);
        }, function(err) {
            if (err instanceof Error && err.message === 'field argument should be an array of valid field objects!')
                return true;
        });
        // Empty array
        test.throws(function() {
            AccountsTemplates.addFields([]);
        }, function(err) {
            if (err instanceof Error && err.message === 'field argument should be an array of valid field objects!')
                return true;
        });

        // Successful add
        var first_name = {
            name: 'first_name',
            displayName: 'First Name',
            type: 'text',
            minLength: 2,
            maxLength: 50,
            required: true
        };
        var last_name = {
            name: 'last_name',
            displayName: 'Last Name',
            type: 'text',
            minLength: 2,
            maxLength: 100,
            required: false
        };
        AccountsTemplates.addFields([first_name, last_name]);
        test.equal(AccountsTemplates.getField('first_name'), first_name);
        test.equal(AccountsTemplates.getField('last_name'), last_name);
        // Now removes ot to be consistend with tests re-run
        AccountsTemplates.removeField('first_name');
        AccountsTemplates.removeField('last_name');
    }
    // Restores initialized state...
    AccountsTemplates._initialized = true;
});

Tinytest.add("AccountsTemplates - setState/getState", function(test) {
    if (Meteor.isServer) {
        // getState does not exist server-side
        test.throws(function() {
            AccountsTemplates.getState();
        });
        // setState does not exist server-side
        test.throws(function() {
            AccountsTemplates.setState();
        });
    } else {
        // Setting 'Sign In'
        AccountsTemplates.setState('sgin');
        test.equal(AccountsTemplates.getState(), 'sgin');
        // Setting 'Sign Up'
        AccountsTemplates.setState('sgup');
        test.equal(AccountsTemplates.getState(), 'sgup');
        // Setting 'Forgot Password'
        AccountsTemplates.setState('fpwd');
        test.equal(AccountsTemplates.getState(), 'fpwd');
        // Setting 'Change Password'
        //AccountsTemplates.setState('cpwd');
        //test.equal(AccountsTemplates.getState(), 'cpwd');
        // Setting an invalid state should throw a Meteor.Error
        test.throws(function() {
            AccountsTemplates.setState('foo');
        }, function(err) {
            if (err instanceof Meteor.Error && err.details == 'accounts-templates-core package got an invalid state value!')
                return true;
        });
    }
});

// -------------------------------------
// TODO: complite the following tests...
// -------------------------------------

Tinytest.add("AccountsTemplates - getFieldError/setFieldError", function(test) {
    if (Meteor.isServer) {
        // getFieldError does not exist server-side
        test.throws(function() {
            AccountsTemplates.getFieldError();
        });
        // setFieldError does not exist server-side
        test.throws(function() {
            AccountsTemplates.setFieldError();
        });
    } else {
        // TODO: write actual tests...
    }
});

Tinytest.add("AccountsTemplates - configure", function(test) {
    if (Meteor.isClient) {
        // configure does not exist client-side
        test.throws(function() {
            AccountsTemplates.configure({});
        });
    } else {
        // TODO: write actual tests...
    }
});
<commit_msg>fixed tests<commit_after>AccountsTemplates.init();

Tinytest.add("AccountsTemplates - addField/removeField", function(test) {
    // Calls after AccountsTemplates.init()
    AccountsTemplates._initialized = true;
    test.throws(function() {
        AccountsTemplates.addField('');
    }, function(err) {
        if (err instanceof Error && err.message === 'AccountsTemplates.addField should strictly be called before AccountsTemplates.init!')
            return true;
    });
    test.throws(function() {
        AccountsTemplates.removeField('');
    }, function(err) {
        if (err instanceof Error && err.message === 'AccountsTemplates.removeField should strictly be called before AccountsTemplates.init!')
            return true;
    });
    AccountsTemplates._initialized = false;

    // Trying to remove a non-existing field
    test.throws(function() {
        AccountsTemplates.removeField('foo');
    }, function(err) {
        if (err instanceof Error && err.message == 'A field called foo does not exist!')
            return true;
    });

    // Trying to remove an existing field
    AccountsTemplates.removeField('email');
    test.isUndefined(AccountsTemplates.getField('email'));

    // Trying to add an already existing field
    test.throws(function() {
        AccountsTemplates.addField(AccountsTemplates.getField('password'));
    }, function(err) {
        if (err instanceof Error && err.message == 'A field called password already exists!')
            return true;
    });

    var login = {
        name: 'login',
        displayName: 'Email',
        type: 'email'
    };

    // Invalid field properties
    test.throws(function() {
        AccountsTemplates.addField(_.extend(_.clone(login), {
            foo: 'bar'
        }));
    }, Error);

    // Successful add
    AccountsTemplates.addField(login);

    // Invalid field.type
    test.throws(function() {
        AccountsTemplates.addField({
            name: 'foo',
            displayName: 'Foo',
            type: 'bar'
        });
    }, function(err) {
        if (err instanceof Error && err.message == 'field.type is not valid!')
            return true;
    });

    // Invalid minLength
    test.throws(function() {
        AccountsTemplates.addField({
            name: 'first-name',
            displayName: 'First Name',
            type: 'text',
            minLength: 0
        });
    }, function(err) {
        if (err instanceof Error && err.message == 'field.minLength should be greater than zero!')
            return true;
    });
    // Invalid maxLength
    test.throws(function() {
        AccountsTemplates.addField({
            name: 'first-name',
            displayName: 'First Name',
            type: 'text',
            maxLength: 0
        });
    }, function(err) {
        if (err instanceof Error && err.message == 'field.maxLength should be greater than zero!')
            return true;
    });
    // maxLength < minLength
    test.throws(function() {
        AccountsTemplates.addField({
            name: 'first-name',
            displayName: 'First Name',
            type: 'text',
            minLength: 2,
            maxLength: 1
        });
    }, function(err) {
        if (err instanceof Error && err.message == 'field.maxLength should be greater than field.maxLength!')
            return true;
    });

    // Successful add
    var first_name = {
        name: 'first_name',
        displayName: 'First Name',
        type: 'text',
        minLength: 2,
        maxLength: 50,
        required: true
    };
    AccountsTemplates.addField(first_name);
    test.equal(AccountsTemplates.getField('first_name'), first_name);
    // Now removes ot to be consistend with tests re-run
    AccountsTemplates.removeField('first_name');
});

Tinytest.add("AccountsTemplates - addFields", function(test) {
    // Fake uninitialized state...
    AccountsTemplates._initialized = false;

    if (Meteor.isClient) {
        // addFields does not exist client-side
        test.throws(function() {
            AccountsTemplates.addFields();
        });
    } else {
        // Not an array of objects
        test.throws(function() {
            AccountsTemplates.addFields('');
        }, function(err) {
            if (err instanceof Error && err.message === 'field argument should be an array of valid field objects!')
                return true;
        });
        test.throws(function() {
            AccountsTemplates.addFields(100);
        }, function(err) {
            if (err instanceof Error && err.message === 'field argument should be an array of valid field objects!')
                return true;
        });
        // Empty array
        test.throws(function() {
            AccountsTemplates.addFields([]);
        }, function(err) {
            if (err instanceof Error && err.message === 'field argument should be an array of valid field objects!')
                return true;
        });

        // Successful add
        var first_name = {
            name: 'first_name',
            displayName: 'First Name',
            type: 'text',
            minLength: 2,
            maxLength: 50,
            required: true
        };
        var last_name = {
            name: 'last_name',
            displayName: 'Last Name',
            type: 'text',
            minLength: 2,
            maxLength: 100,
            required: false
        };
        AccountsTemplates.addFields([first_name, last_name]);
        test.equal(AccountsTemplates.getField('first_name'), first_name);
        test.equal(AccountsTemplates.getField('last_name'), last_name);
        // Now removes ot to be consistend with tests re-run
        AccountsTemplates.removeField('first_name');
        AccountsTemplates.removeField('last_name');
    }
    // Restores initialized state...
    AccountsTemplates._initialized = true;
});

Tinytest.add("AccountsTemplates - setState/getState", function(test) {
    if (Meteor.isServer) {
        // getState does not exist server-side
        test.throws(function() {
            AccountsTemplates.getState();
        });
        // setState does not exist server-side
        test.throws(function() {
            AccountsTemplates.setState();
        });
    } else {
        // Setting 'Sign In'
        AccountsTemplates.setState('sgin');
        test.equal(AccountsTemplates.getState(), 'sgin');
        // Setting 'Sign Up'
        AccountsTemplates.setState('sgup');
        test.equal(AccountsTemplates.getState(), 'sgup');
        // Setting 'Forgot Password'
        AccountsTemplates.setState('fpwd');
        test.equal(AccountsTemplates.getState(), 'fpwd');
        // Setting 'Change Password'
        //AccountsTemplates.setState('cpwd');
        //test.equal(AccountsTemplates.getState(), 'cpwd');
        // Setting an invalid state should throw a Meteor.Error
        test.throws(function() {
            AccountsTemplates.setState('foo');
        }, function(err) {
            if (err instanceof Meteor.Error && err.details == 'accounts-templates-core package got an invalid state value!')
                return true;
        });
    }
});

// -------------------------------------
// TODO: complite the following tests...
// -------------------------------------

Tinytest.add("AccountsTemplates - getFieldError/setFieldError", function(test) {
    if (Meteor.isServer) {
        // getFieldError does not exist server-side
        test.throws(function() {
            AccountsTemplates.getFieldError();
        });
        // setFieldError does not exist server-side
        test.throws(function() {
            AccountsTemplates.setFieldError();
        });
    } else {
        // TODO: write actual tests...
    }
});

Tinytest.add("AccountsTemplates - configure", function(test) {
    if (Meteor.isClient) {
        // configure does not exist client-side
        test.throws(function() {
            AccountsTemplates.configure({});
        });
    } else {
        // TODO: write actual tests...
    }
});
<|endoftext|>


<commit_before>var map;

var noPoi = [
{
    featureType: "poi",
    stylers: [
      { visibility: "off" }
    ]
  },
  {
    featureType: "poi.park",
    stylers: [
      { visibility: "on" }
    ]
  }
];

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 40.754, lng: -73.984},
    zoom: 12
  });
  map.setOptions({styles: noPoi});
}

<commit_msg>added magnolia marker<commit_after>var map;

var noPoi = [
{
    featureType: "poi",
    stylers: [
      { visibility: "off" }
    ]
  },
  {
    featureType: "poi.park",
    stylers: [
      { visibility: "on" }
    ]
  }
];

var magnoliaUWSLatLong  = {lat: 40.775764, lng: -73.9802664}

var contentString = '
'+
  '
'+
  '
'+
  '
Magnolia Upper West Side
'+
  '
'+
  '
Magnolia Upper West Side, best known for it\'s cupcakes, ' +
  'is one of Jeff and Emily\'s go-to desset spots in NYC. '+
  'When Jeff and Emily go here, they recommend getting a '+
  'vanilla cupcake with pink vanilla butter cream. '+
  'They\'re also crazy about Magnolia\'s banana pudding. '+
  'The pudding is a secret speciality at Magnolia, as most people '+
  'only know about the cupcakes.
'+
  '
Learn more here: '+
  'More detailed writeup about Magnolia UWS '+
  '(last visited by Jeff and Emily on August 13, 2015).
'+
  '
'+
  '
';

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {lat: 40.754, lng: -73.984},
    zoom: 12
  });
  map.setOptions({styles: noPoi});

    var magnoliaUWS = new google.maps.Marker({
        position: magnoliaUWSLatLong,
        map: map,
        title: 'Magnolia UWS!'
    });

    magnoliaUWS.addListener('click', function() {
        infowindow.open(map, magnoliaUWS);
    });

    var infowindow = new google.maps.InfoWindow({
        content: contentString
    });
}

<|endoftext|>