<commit_before>require('../support')
import communities from '../../src/reducers/communities'
import {
  FETCH_POST,
  FETCH_POSTS,
  FETCH_CURRENT_USER,
  UPDATE_COMMUNITY_SETTINGS,
  ADD_COMMUNITY_MODERATOR,
  ADD_COMMUNITY_MODERATOR_PENDING,
  REMOVE_COMMUNITY_MODERATOR,
  REMOVE_COMMUNITY_MODERATOR_PENDING,
  UPDATE_COMMUNITY_SETTINGS_PENDING,
  USE_INVITATION
} from '../../src/actions'

const post1 = {
  id: 'a',
  name: 'hi',
  communities: [
    {id: 'c1', slug: 'c1'},
    {id: 'c2', slug: 'c2'}
  ]
}

const post2 = {
  id: 'b',
  name: 'hi',
  communities: [
    {id: 'c3', slug: 'c3'},
    {id: 'c4', slug: 'c4'}
  ]
}

const community1 = {
  id: 'c1',
  slug: 'c1',
  name: 'Current Name',
  moderators: []
}

describe('communities', () => {
  describe('on FETCH_POST', () => {
    it('normalizes community data', () => {
      let action = {
        type: FETCH_POST,
        payload: post1
      }

      let state = {
        c1: {id: 'c1', slug: 'old'},
        c3: {id: 'c3', slug: 'c3'}
      }

      let expectedState = {
        c1: {id: 'c1', slug: 'c1'},
        c2: {id: 'c2', slug: 'c2'},
        c3: {id: 'c3', slug: 'c3'}
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on FETCH_CURRENT_USER', () => {
    it('normalizes community data', () => {
      let action = {
        type: FETCH_CURRENT_USER,
        payload: {
          id: 1,
          memberships: [
            {community: {id: 'c1', slug: 'c1'}},
            {community: {id: 'c2', slug: 'c2'}}
          ]
        }
      }

      let state = {
        c1: {id: 'c1', slug: 'old'},
        c3: {id: 'c3', slug: 'c3'}
      }

      let expectedState = {
        c1: {id: 'c1', slug: 'c1'},
        c2: {id: 'c2', slug: 'c2'},
        c3: {id: 'c3', slug: 'c3'}
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on FETCH_POSTS', () => {
    it('normalizes community data', () => {
      let action = {
        type: FETCH_POSTS,
        payload: {posts: [post1, post2]}
      }

      let state = {
        c1: {id: 'c1', slug: 'old'},
        c4: {id: 'c4', slug: 'c4', hello: 'world'},
        c5: {id: 'c5', slug: 'c5'}
      }

      let expectedState = {
        c1: {id: 'c1', slug: 'c1'},
        c2: {id: 'c2', slug: 'c2'},
        c3: {id: 'c3', slug: 'c3'},
        c4: {id: 'c4', slug: 'c4', hello: 'world'},
        c5: {id: 'c5', slug: 'c5'}
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on UPDATE_COMMUNITY_SETTINGS with error', () => {
    it('restores current community to previous state', () => {
      let action = {
        type: UPDATE_COMMUNITY_SETTINGS,
        error: true,
        meta: {prevProps: community1, slug: community1.slug}
      }

      let state = {
        [community1.slug]: {...community1, name: 'New Name'}
      }

      let expectedState = {
        [community1.slug]: community1
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on ADD_COMMUNITY_MODERATOR with error', () => {
    it('restores current community to previous state', () => {
      let action = {
        type: ADD_COMMUNITY_MODERATOR,
        error: true,
        meta: {prevProps: community1, slug: community1.slug}
      }

      let state = {
        [community1.slug]: {...community1, name: 'Goal', moderators: [{name: 'Joe Mod'}]}
      }

      let expectedState = {
        [community1.slug]: community1
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on REMOVE_COMMUNITY_MODERATOR with error', () => {
    it('restores current community to previous state', () => {
      let prevCommunity = {...community1, moderators: [{name: 'Joe Mod'}]}

      let action = {
        type: REMOVE_COMMUNITY_MODERATOR,
        error: true,
        meta: {prevProps: prevCommunity, slug: community1.slug}
      }

      let state = {
        [community1.slug]: community1
      }

      let expectedState = {
        [community1.slug]: prevCommunity
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on UPDATE_COMMUNITY_SETTINGS_PENDING', () => {
    it('updates the community in the store', () => {
      let action = {
        type: UPDATE_COMMUNITY_SETTINGS_PENDING,
        meta: {
          slug: 'c1',
          params: {
            name: 'New Name',
            settings: {all_can_invite: true}
          }
        }
      }

      let state = {
        c1: {
          slug: 'c1',
          intention: 'Intention.',
          settings: {sends_email_prompts: true}
        }
      }

      let expectedState = {
        c1: {
          slug: 'c1',
          name: 'New Name',
          intention: 'Intention.',
          settings: {sends_email_prompts: true, all_can_invite: true}
        }
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on ADD_COMMUNITY_MODERATOR_PENDING', () => {
    it('updates the community in the store', () => {
      let action = {
        type: ADD_COMMUNITY_MODERATOR_PENDING,
        meta: {moderator: {name: 'Joe Mod'}, slug: 'c1'}
      }

      let state = {
        c1: community1
      }

      let expectedState = {
        c1: {...community1, moderators: [{name: 'Joe Mod'}]}
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on REMOVE_COMMUNITY_MODERATOR_PENDING', () => {
    it('updates the community in the store', () => {
      let action = {
        type: REMOVE_COMMUNITY_MODERATOR_PENDING,
        meta: {moderatorId: 2, slug: 'c1'}
      }

      let state = {
        c1: {...community1, moderators: [{name: 'Joe Mod', id: 1}, {name: 'Sue Mod', id: 2}]}
      }

      let expectedState = {
        c1: {...community1, moderators: [{name: 'Joe Mod', id: 1}]}
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on USE_INVITATION', () => {
    it('adds the community indexed by both token and slug', () => {
      const token = 'abcdef'
      let action = {
        type: USE_INVITATION,
        meta: {token},
        payload: {
          community: community1
        }
      }
      let state = {}

      let expectedState = {
        [community1.slug]: community1,
        [token]: community1
      }
      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })
})
<commit_msg>update test<commit_after>require('../support')
import communities from '../../src/reducers/communities'
import {
  FETCH_POST,
  FETCH_POSTS,
  FETCH_CURRENT_USER,
  UPDATE_COMMUNITY_SETTINGS,
  ADD_COMMUNITY_MODERATOR,
  ADD_COMMUNITY_MODERATOR_PENDING,
  REMOVE_COMMUNITY_MODERATOR,
  REMOVE_COMMUNITY_MODERATOR_PENDING,
  UPDATE_COMMUNITY_SETTINGS_PENDING,
  USE_INVITATION
} from '../../src/actions'

const post1 = {
  id: 'a',
  name: 'hi',
  communities: [
    {id: 'c1', slug: 'c1'},
    {id: 'c2', slug: 'c2'}
  ]
}

const post2 = {
  id: 'b',
  name: 'hi',
  communities: [
    {id: 'c3', slug: 'c3'},
    {id: 'c4', slug: 'c4'}
  ]
}

const community1 = {
  id: 'c1',
  slug: 'c1',
  name: 'Current Name',
  moderators: []
}

describe('communities', () => {
  describe('on FETCH_POST', () => {
    it('normalizes community data', () => {
      let action = {
        type: FETCH_POST,
        payload: post1
      }

      let state = {
        c1: {id: 'c1', slug: 'old'},
        c3: {id: 'c3', slug: 'c3'}
      }

      let expectedState = {
        c1: {id: 'c1', slug: 'c1'},
        c2: {id: 'c2', slug: 'c2'},
        c3: {id: 'c3', slug: 'c3'}
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on FETCH_CURRENT_USER', () => {
    it('normalizes community data', () => {
      let action = {
        type: FETCH_CURRENT_USER,
        payload: {
          id: 1,
          memberships: [
            {community: {id: 'c1', slug: 'c1'}},
            {community: {id: 'c2', slug: 'c2'}}
          ]
        }
      }

      let state = {
        c1: {id: 'c1', slug: 'old'},
        c3: {id: 'c3', slug: 'c3'}
      }

      let expectedState = {
        c1: {id: 'c1', slug: 'c1'},
        c2: {id: 'c2', slug: 'c2'},
        c3: {id: 'c3', slug: 'c3'}
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on FETCH_POSTS', () => {
    it('normalizes community data', () => {
      let action = {
        type: FETCH_POSTS,
        payload: {posts: [post1, post2]}
      }

      let state = {
        c1: {id: 'c1', slug: 'old'},
        c4: {id: 'c4', slug: 'c4', hello: 'world'},
        c5: {id: 'c5', slug: 'c5'}
      }

      let expectedState = {
        c1: {id: 'c1', slug: 'c1'},
        c2: {id: 'c2', slug: 'c2'},
        c3: {id: 'c3', slug: 'c3'},
        c4: {id: 'c4', slug: 'c4', hello: 'world'},
        c5: {id: 'c5', slug: 'c5'}
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on UPDATE_COMMUNITY_SETTINGS with error', () => {
    it('restores current community to previous state', () => {
      let action = {
        type: UPDATE_COMMUNITY_SETTINGS,
        error: true,
        meta: {prevProps: community1, slug: community1.slug}
      }

      let state = {
        [community1.slug]: {...community1, name: 'New Name'}
      }

      let expectedState = {
        [community1.slug]: community1
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on ADD_COMMUNITY_MODERATOR with error', () => {
    it('restores current community to previous state', () => {
      let action = {
        type: ADD_COMMUNITY_MODERATOR,
        error: true,
        meta: {prevProps: community1, slug: community1.slug}
      }

      let state = {
        [community1.slug]: {...community1, name: 'Goal', moderators: [{name: 'Joe Mod'}]}
      }

      let expectedState = {
        [community1.slug]: community1
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on REMOVE_COMMUNITY_MODERATOR with error', () => {
    it('restores current community to previous state', () => {
      let prevCommunity = {...community1, moderators: [{name: 'Joe Mod'}]}

      let action = {
        type: REMOVE_COMMUNITY_MODERATOR,
        error: true,
        meta: {prevProps: prevCommunity, slug: community1.slug}
      }

      let state = {
        [community1.slug]: community1
      }

      let expectedState = {
        [community1.slug]: prevCommunity
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on UPDATE_COMMUNITY_SETTINGS_PENDING', () => {
    it('updates the community in the store', () => {
      let action = {
        type: UPDATE_COMMUNITY_SETTINGS_PENDING,
        meta: {
          slug: 'c1',
          params: {
            name: 'New Name',
            settings: {all_can_invite: true}
          }
        }
      }

      let state = {
        c1: {
          slug: 'c1',
          intention: 'Intention.',
          settings: {sends_email_prompts: true}
        }
      }

      let expectedState = {
        c1: {
          slug: 'c1',
          name: 'New Name',
          intention: 'Intention.',
          settings: {sends_email_prompts: true, all_can_invite: true}
        }
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on ADD_COMMUNITY_MODERATOR_PENDING', () => {
    it('updates the community in the store', () => {
      let action = {
        type: ADD_COMMUNITY_MODERATOR_PENDING,
        meta: {moderator: {name: 'Joe Mod'}, slug: 'c1'}
      }

      let state = {
        c1: community1
      }

      let expectedState = {
        c1: {...community1, moderators: [{name: 'Joe Mod'}]}
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on REMOVE_COMMUNITY_MODERATOR_PENDING', () => {
    it('updates the community in the store', () => {
      let action = {
        type: REMOVE_COMMUNITY_MODERATOR_PENDING,
        meta: {moderatorId: 2, slug: 'c1'}
      }

      let state = {
        c1: {...community1, moderators: [{name: 'Joe Mod', id: 1}, {name: 'Sue Mod', id: 2}]}
      }

      let expectedState = {
        c1: {...community1, moderators: [{name: 'Joe Mod', id: 1}]}
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })

  describe('on USE_INVITATION', () => {
    it('adds the community indexed by both token and slug, preserving existing values', () => {
      const token = 'abcdef'
      let updatedCommunity1 = {slug: community1.slug, newval: 'a new value'}
      let action = {
        type: USE_INVITATION,
        meta: {token},
        payload: {
          community: updatedCommunity1
        }
      }
      let state = {
        [community1.slug]: community1
      }

      let expectedState = {
        [community1.slug]: {...community1, ...updatedCommunity1},
        [token]: updatedCommunity1
      }

      expect(communities(state, action)).to.deep.equal(expectedState)
    })
  })
})
<|endoftext|>


<commit_before>'use strict';

function attachEvents() {
  node
    .on('mouseover', function(d) {
      if (!mousedown_node || d === mousedown_node) {
        return;
      }
      // enlarge target node
      d3.select(this)
        .attr('transform', d3.select(this).attr('transform') + ' scale(1.1)');
    })
    .on('mouseout', function(d) {
      if (!mousedown_node || d === mousedown_node) {
        return;
      }
      // unenlarge target node
      d3.select(this)
        .attr('transform',
          d3.select(this).attr('transform').replace(' scale(1.1)', ''));
    })
    .on('mousedown', function(d) {
      if (d3.event.ctrlKey) {
        return;
      }

      // select node
      mousedown_node = d;
      if (mousedown_node === selected_node) {
        selected_node = null;
      }
      else selected_node = mousedown_node;
      selected_link = null;

      // reposition drag line
      drag_line
        .classed('hidden', false)
        .attr({
          'x1': mousedown_node.x,
          'y1': mousedown_node.y,
          'x2': mousedown_node.x,
          'y2': mousedown_node.y
        });

      restart();
      attachEvents()
    })
    .on('mouseup', function(d) {
      if (!mousedown_node) {
        return;
      }

      // needed by FF
      drag_line
        .classed('hidden', true)
        .style('marker-end', '');

      // check for drag-to-self
      mouseup_node = d;
      if (mouseup_node === mousedown_node) {
        editing = true;
        editNode(d);
        resetMouseVars();
        return;
      }

      // unenlarge target node
      d3.select(this).attr('transform', '');

      // add link to graph (update if exists)
      // NB: links are strictly source < target; arrows separately specified by booleans
      var source, target,
          source = mousedown_node;
          target = mouseup_node;

      var link = addLink(source, target)

      // select new link
      selected_link = link;
      selected_node = null;
      restart();
      attachEvents();
    });

  path
    .on('mousedown', function(d) {
      if (d3.event.ctrlKey) {
        return;
      }

      // select link
      mousedown_link = d;
      if (mousedown_link === selected_link) {
        selected_link = null;
      } else {
        selected_link = mousedown_link;
      }
      selected_node = null;
      editLink(d);
      resetMouseVars();
      restart();
    });
}

function resetMouseVars() {
  mousedown_node = null;
  mouseup_node = null;
  mousedown_link = null;
}

function resetMenus() {
  d3.select('#node-menu').style('display', 'none');
  d3.select('#link-menu').style('display', 'none');
}

function writeGraph() {
  d3.select('#graph-field').html(JSON.stringify(window.graph));
}

function spliceLinksForNode(node) {
  var toSplice = window.graph.links.filter(function(l) {
    return (l.source === node || l.target === node);
  });
  toSplice.map(function(l) {
    window.graph.links.splice(window.graph.links.indexOf(l), 1);
  });
}

function mousedown() {
  // prevent I-bar on drag
  //d3.event.preventDefault();

  // because :active only works in WebKit?
  svg.classed('active', true);

  if (d3.event.ctrlKey || d3.event.toElement.nodeName !== 'svg') {
    return;
  }

  // insert new node at point
  var point = d3.mouse(this)
  addNode(point);

  restart();
  attachEvents();
}

function addNode(point) {
  var newNode = {
    id: ++window.graph.lastId,
    name: 'New ' + window.graph.lastId,
    x: width / 2,
    y: height / 2,
    r: 12
  };
  if (point) {
    newNode.x = point[0];
    newNode.y = point[1];
  }
  window.graph.nodes.push(newNode);
  return newNode;
}

function addLink(source, target) {
  var link = window.graph.links.filter(function(l) {
    return (l.source === source && l.target === target) ||
      (l.source === target && l.target === source);
  })[0];

  if (link) {
    return link;
  } else {
    link = {
      source: source,
      target: target,
      strength: 10
    };
    window.graph.links.push(link);
  }
}

function mousemove() {
  if (!mousedown_node) {
    return;
  }

  // update drag line
  var point = d3.mouse(this);
  drag_line
    .attr({
      'x1': mousedown_node.x,
      'y1': mousedown_node.y,
      'x2': point[0],
      'y2': point[1]
    });

  attachEvents();
  restart();
}

function mouseup() {
  if (mousedown_node) {
    // hide drag line
    drag_line
      .classed('hidden', true)
      .style('marker-end', '');
  }
  if (editing) {
    return;
  }

  // because :active only works in WebKit?
  svg.classed('active', false);

  // clear mouse event vars
  resetMouseVars();
}

// only respond once per keydown
var lastKeyDown = -1;

function keydown() {
  if (lastKeyDown !== -1) {
    return;
  }
  lastKeyDown = d3.event.keyCode;

  // ctrl
  if(d3.event.keyCode === 17) {
    node.call(force.drag);
    svg.classed('ctrl', true);
  }
}

function keyup() {
  lastKeyDown = -1;

  // ctrl
  if (d3.event.keyCode === 17) {
    node
      .on('mousedown.drag', null)
      .on('touchstart.drag', null);
    svg.classed('ctrl', false);
  }
}

function editNode(d) {
  d3.select('#link-menu').style('display', 'none');
  var nodeMenu = d3.select('#node-menu');
  nodeMenu.style('display', 'block');
  nodeMenu.select('#edit-node-name')
    .attr('value', d.name)
    .on('keyup', function() {
      window.graph.nodes.filter(function(node) {
        return node === d;
      })[0].name = this.value;
      restart();
    });
  nodeMenu.select('#edit-node-r')
    .attr('value', d.r)
    .on('input', function() {
      window.graph.nodes.filter(function(node) {
        return node.id === d.id;
      })[0].r = this.value;
      restart();
    });
  nodeMenu.select('#edit-node-dashed')
    .property('checked', d.dashed)
    .on('change', function() {
      window.graph.nodes.filter(function(link) {
        return link === d;
      })[0].dashed = d3.select(this).property('checked');
      restart();
    });
  nodeMenu.select('#delete-node')
    .on('click', function() {
      if (selected_node) {
        window.graph.nodes
          .splice(window.graph.nodes.indexOf(selected_node), 1);
        spliceLinksForNode(selected_node);
      }
      selected_link = null;
      selected_node = null;
      restart();
      attachEvents();
      nodeMenu.style('display', 'none');
    });
}

function editLink(d) {
  d3.select('#node-menu').style('display', 'none');
  var linkMenu = d3.select('#link-menu');
  linkMenu.style('display', 'block');
  linkMenu.select('#source-name').text(d.source.name);
  linkMenu.select('#target-name').text(d.target.name);
  linkMenu.select('#edit-center-text')
    .attr('value', d.centerText ? d.centerText : '')
    .on('keyup', function() {
      window.graph.links.filter(function(link) {
        return link === d;
      })[0].centerText = this.value;
      restart();
    });
  linkMenu.select('#edit-source-text')
    .attr('value', d.sourceText ? d.sourceText : '')
    .on('keyup', function() {
      window.graph.links.filter(function(link) {
        return link === d;
      })[0].sourceText = this.value;
      restart();
    });
  linkMenu.select('#edit-target-text')
    .attr('value', d.targetText ? d.targetText : '')
    .on('keyup', function() {
      window.graph.links.filter(function(link) {
        return link === d;
      })[0].targetText = this.value;
      restart();
    });
  linkMenu.select('#edit-strength')
    .attr('value', d.strength)
    .on('input', function() {
      window.graph.links.filter(function(link) {
        return link === d;
      })[0].strength = this.value;
      restart();
    });
  linkMenu.select('#edit-link-dashed')
    .property('checked', d.dashed)
    .on('change', function() {
      window.graph.links.filter(function(link) {
        return link === d;
      })[0].dashed = d3.select(this).property('checked');
      restart();
    });
  linkMenu.select('#delete-link')
    .on('click', function() {
      if (selected_link) {
        window.graph.links
          .splice(window.graph.links.indexOf(selected_link), 1);
      }
      selected_link = null;
      selected_node = null;
      restart();
      attachEvents();
      linkMenu.style('display', 'none');
    });
}

function addTemplate(template) {
  var parts = template.split(';');
  var nodes = parts[0].split(',');
  var links = parts[1].split(',');
  var builtNodes = {};
  nodes.forEach(function(d) {
    builtNodes[d] = addNode(null);
  });
  links.forEach(function(d) {
    var linkParts = d.split('-');
    addLink(builtNodes[linkParts[0]], builtNodes[linkParts[1]]);
  })

  restart();
  attachEvents();
}

svg.on('mousedown', mousedown)
  .on('mousemove', mousemove)
  .on('mouseup', mouseup);
d3.select(window)
  .on('keydown', keydown)
  .on('keyup', keyup);
d3.select('.expand-help').on('click', function(e) {
  d3.event.preventDefault();
  var body = d3.select('.instructions .body');
  body.classed('hidden', !body.classed('hidden'));
});
<commit_msg>Selecting a node should actually change the values in the edit pane<commit_after>'use strict';

function attachEvents() {
  node
    .on('mouseover', function(d) {
      if (!mousedown_node || d === mousedown_node) {
        return;
      }
      // enlarge target node
      d3.select(this)
        .attr('transform', d3.select(this).attr('transform') + ' scale(1.1)');
    })
    .on('mouseout', function(d) {
      if (!mousedown_node || d === mousedown_node) {
        return;
      }
      // unenlarge target node
      d3.select(this)
        .attr('transform',
          d3.select(this).attr('transform').replace(' scale(1.1)', ''));
    })
    .on('mousedown', function(d) {
      if (d3.event.ctrlKey) {
        return;
      }

      // select node
      mousedown_node = d;
      if (mousedown_node === selected_node) {
        selected_node = null;
      }
      else selected_node = mousedown_node;
      selected_link = null;

      // reposition drag line
      drag_line
        .classed('hidden', false)
        .attr({
          'x1': mousedown_node.x,
          'y1': mousedown_node.y,
          'x2': mousedown_node.x,
          'y2': mousedown_node.y
        });

      restart();
      attachEvents()
    })
    .on('mouseup', function(d) {
      if (!mousedown_node) {
        return;
      }

      // needed by FF
      drag_line
        .classed('hidden', true)
        .style('marker-end', '');

      // check for drag-to-self
      mouseup_node = d;
      if (mouseup_node === mousedown_node) {
        editing = true;
        editNode(d);
        resetMouseVars();
        return;
      }

      // unenlarge target node
      d3.select(this).attr('transform', '');

      // add link to graph (update if exists)
      // NB: links are strictly source < target; arrows separately specified by booleans
      var source, target,
          source = mousedown_node;
          target = mouseup_node;

      var link = addLink(source, target)

      // select new link
      selected_link = link;
      selected_node = null;
      restart();
      attachEvents();
    });

  path
    .on('mousedown', function(d) {
      if (d3.event.ctrlKey) {
        return;
      }

      // select link
      mousedown_link = d;
      if (mousedown_link === selected_link) {
        selected_link = null;
      } else {
        selected_link = mousedown_link;
      }
      selected_node = null;
      editLink(d);
      resetMouseVars();
      restart();
    });
}

function resetMouseVars() {
  mousedown_node = null;
  mouseup_node = null;
  mousedown_link = null;
}

function resetMenus() {
  d3.select('#node-menu').style('display', 'none');
  d3.select('#link-menu').style('display', 'none');
}

function writeGraph() {
  d3.select('#graph-field').html(JSON.stringify(window.graph));
}

function spliceLinksForNode(node) {
  var toSplice = window.graph.links.filter(function(l) {
    return (l.source === node || l.target === node);
  });
  toSplice.map(function(l) {
    window.graph.links.splice(window.graph.links.indexOf(l), 1);
  });
}

function mousedown() {
  // prevent I-bar on drag
  //d3.event.preventDefault();

  // because :active only works in WebKit?
  svg.classed('active', true);

  if (d3.event.ctrlKey || d3.event.toElement.nodeName !== 'svg') {
    return;
  }

  // insert new node at point
  var point = d3.mouse(this)
  addNode(point);

  restart();
  attachEvents();
}

function addNode(point) {
  var newNode = {
    id: ++window.graph.lastId,
    name: 'New ' + window.graph.lastId,
    x: width / 2,
    y: height / 2,
    r: 12
  };
  if (point) {
    newNode.x = point[0];
    newNode.y = point[1];
  }
  window.graph.nodes.push(newNode);
  return newNode;
}

function addLink(source, target) {
  var link = window.graph.links.filter(function(l) {
    return (l.source === source && l.target === target) ||
      (l.source === target && l.target === source);
  })[0];

  if (link) {
    return link;
  } else {
    link = {
      source: source,
      target: target,
      strength: 10
    };
    window.graph.links.push(link);
  }
}

function mousemove() {
  if (!mousedown_node) {
    return;
  }

  // update drag line
  var point = d3.mouse(this);
  drag_line
    .attr({
      'x1': mousedown_node.x,
      'y1': mousedown_node.y,
      'x2': point[0],
      'y2': point[1]
    });

  attachEvents();
  restart();
}

function mouseup() {
  if (mousedown_node) {
    // hide drag line
    drag_line
      .classed('hidden', true)
      .style('marker-end', '');
  }
  if (editing) {
    return;
  }

  // because :active only works in WebKit?
  svg.classed('active', false);

  // clear mouse event vars
  resetMouseVars();
}

// only respond once per keydown
var lastKeyDown = -1;

function keydown() {
  if (lastKeyDown !== -1) {
    return;
  }
  lastKeyDown = d3.event.keyCode;

  // ctrl
  if(d3.event.keyCode === 17) {
    node.call(force.drag);
    svg.classed('ctrl', true);
  }
}

function keyup() {
  lastKeyDown = -1;

  // ctrl
  if (d3.event.keyCode === 17) {
    node
      .on('mousedown.drag', null)
      .on('touchstart.drag', null);
    svg.classed('ctrl', false);
  }
}

function editNode(d) {
  d3.select('#link-menu').style('display', 'none');
  var nodeMenu = d3.select('#node-menu');
  nodeMenu.style('display', 'block');
  document.getElementById('edit-node-name').value = d.name;
  nodeMenu.select('#edit-node-name')
    .on('keyup', function() {
      window.graph.nodes.filter(function(node) {
        return node === d;
      })[0].name = this.value;
      restart();
    });
  document.getElementById('edit-node-r').value = d.r;
  nodeMenu.select('#edit-node-r')
    .on('input', function() {
      window.graph.nodes.filter(function(node) {
        return node.id === d.id;
      })[0].r = this.value;
      restart();
    });
  document.getElementById('edit-node-dashed').checked = d.dashed;
  nodeMenu.select('#edit-node-dashed')
    .on('change', function() {
      window.graph.nodes.filter(function(link) {
        return link === d;
      })[0].dashed = d3.select(this).property('checked');
      restart();
    });
  nodeMenu.select('#delete-node')
    .on('click', function() {
      if (selected_node) {
        window.graph.nodes
          .splice(window.graph.nodes.indexOf(selected_node), 1);
        spliceLinksForNode(selected_node);
      }
      selected_link = null;
      selected_node = null;
      restart();
      attachEvents();
      nodeMenu.style('display', 'none');
    });
}

function editLink(d) {
  d3.select('#node-menu').style('display', 'none');
  var linkMenu = d3.select('#link-menu');
  linkMenu.style('display', 'block');
  linkMenu.select('#source-name').text(d.source.name);
  linkMenu.select('#target-name').text(d.target.name);
  linkMenu.select('#edit-center-text')
    .attr('value', d.centerText ? d.centerText : '')
    .on('keyup', function() {
      window.graph.links.filter(function(link) {
        return link === d;
      })[0].centerText = this.value;
      restart();
    });
  linkMenu.select('#edit-source-text')
    .attr('value', d.sourceText ? d.sourceText : '')
    .on('keyup', function() {
      window.graph.links.filter(function(link) {
        return link === d;
      })[0].sourceText = this.value;
      restart();
    });
  linkMenu.select('#edit-target-text')
    .attr('value', d.targetText ? d.targetText : '')
    .on('keyup', function() {
      window.graph.links.filter(function(link) {
        return link === d;
      })[0].targetText = this.value;
      restart();
    });
  linkMenu.select('#edit-strength')
    .attr('value', d.strength)
    .on('input', function() {
      window.graph.links.filter(function(link) {
        return link === d;
      })[0].strength = this.value;
      restart();
    });
  linkMenu.select('#edit-link-dashed')
    .property('checked', d.dashed)
    .on('change', function() {
      window.graph.links.filter(function(link) {
        return link === d;
      })[0].dashed = d3.select(this).property('checked');
      restart();
    });
  linkMenu.select('#delete-link')
    .on('click', function() {
      if (selected_link) {
        window.graph.links
          .splice(window.graph.links.indexOf(selected_link), 1);
      }
      selected_link = null;
      selected_node = null;
      restart();
      attachEvents();
      linkMenu.style('display', 'none');
    });
}

function addTemplate(template) {
  var parts = template.split(';');
  var nodes = parts[0].split(',');
  var links = parts[1].split(',');
  var builtNodes = {};
  nodes.forEach(function(d) {
    builtNodes[d] = addNode(null);
  });
  links.forEach(function(d) {
    var linkParts = d.split('-');
    addLink(builtNodes[linkParts[0]], builtNodes[linkParts[1]]);
  })

  restart();
  attachEvents();
}

svg.on('mousedown', mousedown)
  .on('mousemove', mousemove)
  .on('mouseup', mouseup);
d3.select(window)
  .on('keydown', keydown)
  .on('keyup', keyup);
d3.select('.expand-help').on('click', function(e) {
  d3.event.preventDefault();
  var body = d3.select('.instructions .body');
  body.classed('hidden', !body.classed('hidden'));
});
<|endoftext|>


<commit_before>/**
 * Copyright 2018-present Facebook.
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 * @format
 */

const [s, ns] = process.hrtime();
let launchStartTime = s * 1e3 + ns / 1e6;

const {app, BrowserWindow, ipcMain} = require('electron');
const path = require('path');
const url = require('url');
const fs = require('fs');
const {exec} = require('child_process');
const compilePlugins = require('./compilePlugins.js');
const os = require('os');

// disable electron security warnings: https://github.com/electron/electron/blob/master/docs/tutorial/security.md#security-native-capabilities-and-your-responsibility
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true;

if (!process.env.ANDROID_HOME) {
  process.env.ANDROID_HOME = '/opt/android_sdk';
}

if (process.platform === 'darwin') {
  // If we are running on macOS and the app is called Flipper, we add a comment
  // with the old name, to make it findable via Spotlight using its old name.
  const APP_NAME = 'Flipper.app';
  const i = process.execPath.indexOf(`/${APP_NAME}/`);
  if (i > -1) {
    exec(
      `osascript -e 'on run {f, c}' -e 'tell app "Finder" to set comment of (POSIX file f as alias) to c' -e end "${process.execPath.substr(
        0,
        i,
      )}/${APP_NAME}" "sonar"`,
    );
  }
}

// ensure .flipper folder and config exist
const sonarDir = path.join(os.homedir(), '.sonar');
const flipperDir = path.join(os.homedir(), '.flipper');
if (fs.existsSync(flipperDir)) {
  // nothing to do
} else if (fs.existsSync(sonarDir)) {
  // move .sonar to .flipper
  fs.renameSync(sonarDir, flipperDir);
} else {
  fs.mkdirSync(flipperDir);
}

const configPath = path.join(flipperDir, 'config.json');
let config = {pluginPaths: [], disabledPlugins: [], lastWindowPosition: {}};

try {
  config = {
    ...config,
    ...JSON.parse(fs.readFileSync(configPath)),
  };
} catch (e) {
  fs.writeFileSync(configPath, JSON.stringify(config));
}

const pluginPaths = config.pluginPaths
  .concat(
    path.join(__dirname, '..', 'src', 'plugins'),
    path.join(__dirname, '..', 'src', 'fb', 'plugins'),
  )
  .map(p => p.replace(/^~/, os.homedir()))
  .filter(fs.existsSync);

process.env.CONFIG = JSON.stringify({
  ...config,
  pluginPaths,
});

// possible reference to main app window
let win;
let appReady = false;
let pluginsCompiled = false;

// tracking
setInterval(() => {
  if (win && win.isFocused()) {
    win.webContents.send('trackUsage');
  }
}, 60 * 1000);

compilePlugins(
  () => {
    if (win) {
      win.reload();
    }
  },
  pluginPaths,
  path.join(flipperDir, 'plugins'),
).then(dynamicPlugins => {
  process.env.PLUGINS = JSON.stringify(dynamicPlugins);
  pluginsCompiled = true;
  tryCreateWindow();
});

// check if we already have an instance of this app open
const isSecondInstance = app.makeSingleInstance(
  (commandLine, workingDirectory) => {
    // someone tried to run a second instance, we should focus our window
    if (win) {
      if (win.isMinimized()) {
        win.restore();
      }

      win.focus();
    }
  },
);

// if this is a second instance then quit the app to prevent collisions
if (isSecondInstance) {
  app.quit();
}

// quit app once all windows are closed
app.on('window-all-closed', () => {
  appReady = false;
  app.quit();
});

app.on('ready', function() {
  appReady = true;
  app.commandLine.appendSwitch('scroll-bounce');
  tryCreateWindow();
  // if in development install the react devtools extension
  if (process.env.NODE_ENV === 'development') {
    const {
      default: installExtension,
      REACT_DEVELOPER_TOOLS,
      REDUX_DEVTOOLS,
    } = require('electron-devtools-installer');
    installExtension(REACT_DEVELOPER_TOOLS.id);
    installExtension(REDUX_DEVTOOLS.id);
  }
});

ipcMain.on('getLaunchTime', event => {
  if (launchStartTime) {
    event.sender.send('getLaunchTime', launchStartTime);
    // set launchTime to null to only report it once, to prevents reporting wrong
    // launch times for example after reloading the renderer process
    launchStartTime = null;
  }
});

function tryCreateWindow() {
  if (appReady && pluginsCompiled) {
    win = new BrowserWindow({
      show: false,
      title: 'Flipper',
      width: config.lastWindowPosition.width || 1400,
      height: config.lastWindowPosition.height || 1000,
      minWidth: 800,
      minHeight: 600,
      center: true,
      backgroundThrottling: false,
      titleBarStyle: 'hiddenInset',
      vibrancy: 'sidebar',
      webPreferences: {
        webSecurity: false,
        scrollBounce: true,
        experimentalFeatures: true,
      },
    });
    win.once('ready-to-show', () => win.show());
    win.once('close', ({sender}) => {
      const [x, y] = sender.getPosition();
      const [width, height] = sender.getSize();
      // save window position and size
      fs.writeFileSync(
        configPath,
        JSON.stringify({
          ...config,
          lastWindowPosition: {
            x,
            y,
            width,
            height,
          },
        }),
      );
    });
    if (config.lastWindowPosition.x && config.lastWindowPosition.y) {
      win.setPosition(config.lastWindowPosition.x, config.lastWindowPosition.y);
    }
    const entryUrl =
      process.env.ELECTRON_URL ||
      url.format({
        pathname: path.join(__dirname, 'index.html'),
        protocol: 'file:',
        slashes: true,
      });
    win.loadURL(entryUrl);
  }
}
<commit_msg>Register flipper: scheme for deeplink<commit_after>/**
 * Copyright 2018-present Facebook.
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 * @format
 */

const [s, ns] = process.hrtime();
let launchStartTime = s * 1e3 + ns / 1e6;

const {app, BrowserWindow, ipcMain} = require('electron');
const path = require('path');
const url = require('url');
const fs = require('fs');
const {exec} = require('child_process');
const compilePlugins = require('./compilePlugins.js');
const os = require('os');
// disable electron security warnings: https://github.com/electron/electron/blob/master/docs/tutorial/security.md#security-native-capabilities-and-your-responsibility
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true;

if (!process.env.ANDROID_HOME) {
  process.env.ANDROID_HOME = '/opt/android_sdk';
}

if (process.platform === 'darwin') {
  // If we are running on macOS and the app is called Flipper, we add a comment
  // with the old name, to make it findable via Spotlight using its old name.
  const APP_NAME = 'Flipper.app';
  const i = process.execPath.indexOf(`/${APP_NAME}/`);
  if (i > -1) {
    exec(
      `osascript -e 'on run {f, c}' -e 'tell app "Finder" to set comment of (POSIX file f as alias) to c' -e end "${process.execPath.substr(
        0,
        i,
      )}/${APP_NAME}" "sonar"`,
    );
  }
}

// ensure .flipper folder and config exist
const sonarDir = path.join(os.homedir(), '.sonar');
const flipperDir = path.join(os.homedir(), '.flipper');
if (fs.existsSync(flipperDir)) {
  // nothing to do
} else if (fs.existsSync(sonarDir)) {
  // move .sonar to .flipper
  fs.renameSync(sonarDir, flipperDir);
} else {
  fs.mkdirSync(flipperDir);
}

const configPath = path.join(flipperDir, 'config.json');
let config = {pluginPaths: [], disabledPlugins: [], lastWindowPosition: {}};

try {
  config = {
    ...config,
    ...JSON.parse(fs.readFileSync(configPath)),
  };
} catch (e) {
  fs.writeFileSync(configPath, JSON.stringify(config));
}

const pluginPaths = config.pluginPaths
  .concat(
    path.join(__dirname, '..', 'src', 'plugins'),
    path.join(__dirname, '..', 'src', 'fb', 'plugins'),
  )
  .map(p => p.replace(/^~/, os.homedir()))
  .filter(fs.existsSync);

process.env.CONFIG = JSON.stringify({
  ...config,
  pluginPaths,
});

// possible reference to main app window
let win;
let appReady = false;
let pluginsCompiled = false;
let deeplinkURL = null;

// tracking
setInterval(() => {
  if (win && win.isFocused()) {
    win.webContents.send('trackUsage');
  }
}, 60 * 1000);

compilePlugins(
  () => {
    if (win) {
      win.reload();
    }
  },
  pluginPaths,
  path.join(flipperDir, 'plugins'),
).then(dynamicPlugins => {
  process.env.PLUGINS = JSON.stringify(dynamicPlugins);
  pluginsCompiled = true;
  tryCreateWindow();
});

// check if we already have an instance of this app open
const isSecondInstance = app.makeSingleInstance(
  (commandLine, workingDirectory) => {
    // someone tried to run a second instance, we should focus our window
    if (win) {
      if (win.isMinimized()) {
        win.restore();
      }

      win.focus();
    }
  },
);

// if this is a second instance then quit the app to prevent collisions
if (isSecondInstance) {
  app.quit();
}

// quit app once all windows are closed
app.on('window-all-closed', () => {
  appReady = false;
  app.quit();
});

app.on('will-finish-launching', () => {
  // Protocol handler for osx
  app.on('open-url', function(event, url) {
    event.preventDefault();
    deeplinkURL = url;
    if (win) {
      win.webContents.send('flipper-deeplink', deeplinkURL);
    }
  });
});

app.on('ready', function() {
  appReady = true;
  app.commandLine.appendSwitch('scroll-bounce');
  tryCreateWindow();
  // if in development install the react devtools extension
  if (process.env.NODE_ENV === 'development') {
    const {
      default: installExtension,
      REACT_DEVELOPER_TOOLS,
      REDUX_DEVTOOLS,
    } = require('electron-devtools-installer');
    installExtension(REACT_DEVELOPER_TOOLS.id);
    installExtension(REDUX_DEVTOOLS.id);
  }
});

ipcMain.on('getLaunchTime', event => {
  if (launchStartTime) {
    event.sender.send('getLaunchTime', launchStartTime);
    // set launchTime to null to only report it once, to prevents reporting wrong
    // launch times for example after reloading the renderer process
    launchStartTime = null;
  }
});

// Define custom protocol handler. Deep linking works on packaged versions of the application!
app.setAsDefaultProtocolClient('flipper');

function tryCreateWindow() {
  if (appReady && pluginsCompiled) {
    win = new BrowserWindow({
      show: false,
      title: 'Flipper',
      width: config.lastWindowPosition.width || 1400,
      height: config.lastWindowPosition.height || 1000,
      minWidth: 800,
      minHeight: 600,
      center: true,
      backgroundThrottling: false,
      titleBarStyle: 'hiddenInset',
      vibrancy: 'sidebar',
      webPreferences: {
        webSecurity: false,
        scrollBounce: true,
        experimentalFeatures: true,
      },
    });
    win.once('ready-to-show', () => win.show());
    win.once('close', ({sender}) => {
      if (process.env.NODE_ENV === 'development') {
        // Removes as a default protocol for debug builds. Because even when the
        // production application is installed, and one tries to deeplink through
        // browser, it still looks for the debug one and tries to open electron
        app.removeAsDefaultProtocolClient('flipper');
      }
      const [x, y] = sender.getPosition();
      const [width, height] = sender.getSize();
      // save window position and size
      fs.writeFileSync(
        configPath,
        JSON.stringify({
          ...config,
          lastWindowPosition: {
            x,
            y,
            width,
            height,
          },
        }),
      );
    });
    if (config.lastWindowPosition.x && config.lastWindowPosition.y) {
      win.setPosition(config.lastWindowPosition.x, config.lastWindowPosition.y);
    }
    const entryUrl =
      process.env.ELECTRON_URL ||
      url.format({
        pathname: path.join(__dirname, 'index.html'),
        protocol: 'file:',
        slashes: true,
      });
    win.loadURL(entryUrl);
    if (deeplinkURL) {
      win.webContents.send('flipper-deeplink', deeplinkURL);
    }
  }
}
<|endoftext|>


<commit_before>'use strict';

describe('mantis adapter tests', function () {
	const expect = require('chai').expect;
	const adapter = require('src/adapters/mantis.js');
	const bidmanager = require('src/bidmanager');
	const adloader = require('src/adloader');
	const constants = require('src/constants.json');

	var mantis, sandbox;

	beforeEach(() => {
		mantis = new adapter();
		sandbox = sinon.sandbox.create();
	});

	afterEach(() => {
		sandbox.restore();

		delete window.context;
		delete window.mantis_link;
		delete window.mantis_breakpoint;
		delete window.mantis_uuid;
	});

	var callBidExample = {
		bidderCode: 'mantis',
		bids: [
			{
				bidId: 'bidId1',
				bidder: 'mantis',
				placementCode: 'foo',
				sizes: [[728, 90]],
				params: {
					property: '1234'
				}
			},
			{
				bidId: 'bidId2',
				bidder: 'mantis',
				placementCode: 'bar',
				sizes: [[300, 600], [300, 250]],
				params: {
					property: '1234'
				}
			}
		]
	};

	describe('callBids', () => {
		it('should create appropriate bid responses', () => {
			sandbox.stub(bidmanager, 'addBidResponse');
			sandbox.stub(adloader, 'loadScript', function (url) {
				var jsonp = eval(decodeURIComponent(url.match(/jsonp=(.*)&property/)[1]));

				jsonp({
					ads: {
						bidId1: {
							cpm: 1,
							html: '<script></script>',
							width: 300,
							height: 600
						}
					}
				});
			});

			mantis.callBids(callBidExample);

			sinon.assert.calledTwice(bidmanager.addBidResponse);

			expect(bidmanager.addBidResponse.firstCall.args[0]).to.eql('foo');

			var bid1 = bidmanager.addBidResponse.firstCall.args[1];
			expect(bid1.getStatusCode()).to.eql(constants.STATUS.GOOD);
			expect(bid1.bidderCode).to.eql('mantis');
			expect(bid1.cpm).to.eql(1);
			expect(bid1.ad).to.eql('<script></script>');
			expect(bid1.width).to.eql(300);
			expect(bid1.height).to.eql(600);

			expect(bidmanager.addBidResponse.secondCall.args[0]).to.eql('bar');

			var bid2 = bidmanager.addBidResponse.secondCall.args[1];
			expect(bid2.getStatusCode()).to.eql(constants.STATUS.NO_BID);
			expect(bid2.bidderCode).to.eql('mantis');
		});

		it('should load script with relevant bid data', () => {
			sandbox.stub(adloader, 'loadScript');

			mantis.callBids(callBidExample);

			sinon.assert.calledOnce(adloader.loadScript);

			var serverCall = adloader.loadScript.firstCall.args[0];

			expect(serverCall).to.match(/buster=[0-9]+&/);
			expect(serverCall).to.match(/tz=[0-9]+&/);
			expect(serverCall).to.match(/secure=(true|false)&/);
			expect(serverCall).to.string('property=1234&');
			expect(serverCall).to.string('bids[0][bidId]=bidId1&');
			expect(serverCall).to.string('bids[0][sizes][0][width]=728&');
			expect(serverCall).to.string('bids[0][sizes][0][height]=90&');
			expect(serverCall).to.string('bids[1][bidId]=bidId2&');
			expect(serverCall).to.string('bids[1][sizes][0][width]=300&');
			expect(serverCall).to.string('bids[1][sizes][0][height]=600&');
			expect(serverCall).to.string('bids[1][sizes][1][width]=300&');
			expect(serverCall).to.string('bids[1][sizes][1][height]=250&');
			expect(serverCall).to.string('version=1');
		});

		/* tests below are to just adhere to code coverage requirements, but it is already tested in our own libraries/deployment process */
		it('should send uuid from window if set', () => {
			sandbox.stub(adloader, 'loadScript');

			window.mantis_uuid = '4321';

			mantis.callBids(callBidExample);

			sinon.assert.calledOnce(adloader.loadScript);

			var serverCall = adloader.loadScript.firstCall.args[0];

			expect(serverCall).to.string('uuid=4321&');
		});

		it('should send mobile = true if breakpoint is hit', () => {
			sandbox.stub(adloader, 'loadScript');

			window.mantis_link = true; // causes iframe detection to not work
			window.mantis_breakpoint = 100000000; // force everything to be mobile

			mantis.callBids(callBidExample);

			sinon.assert.calledOnce(adloader.loadScript);

			var serverCall = adloader.loadScript.firstCall.args[0];

			expect(serverCall).to.string('mobile=true&');
		});

		it('should send different params if amp is detected', () => {
			sandbox.stub(adloader, 'loadScript');

			window.context = {
				tagName: "AMP-AD",
				location: {
					href: 'bar',
					referrer: 'baz'
				}
			};

			mantis.callBids(callBidExample);

			sinon.assert.calledOnce(adloader.loadScript);

			var serverCall = adloader.loadScript.firstCall.args[0];

			expect(serverCall).to.string('mobile=true&');
			expect(serverCall).to.string('url=bar&');
		});
	});
});

<commit_msg>Fix Mantis tests in negative timezone (#1049)<commit_after>'use strict';

describe('mantis adapter tests', function () {
	const expect = require('chai').expect;
	const adapter = require('src/adapters/mantis.js');
	const bidmanager = require('src/bidmanager');
	const adloader = require('src/adloader');
	const constants = require('src/constants.json');

	var mantis, sandbox;

	beforeEach(() => {
		mantis = new adapter();
		sandbox = sinon.sandbox.create();
	});

	afterEach(() => {
		sandbox.restore();

		delete window.context;
		delete window.mantis_link;
		delete window.mantis_breakpoint;
		delete window.mantis_uuid;
	});

	var callBidExample = {
		bidderCode: 'mantis',
		bids: [
			{
				bidId: 'bidId1',
				bidder: 'mantis',
				placementCode: 'foo',
				sizes: [[728, 90]],
				params: {
					property: '1234'
				}
			},
			{
				bidId: 'bidId2',
				bidder: 'mantis',
				placementCode: 'bar',
				sizes: [[300, 600], [300, 250]],
				params: {
					property: '1234'
				}
			}
		]
	};

	describe('callBids', () => {
		it('should create appropriate bid responses', () => {
			sandbox.stub(bidmanager, 'addBidResponse');
			sandbox.stub(adloader, 'loadScript', function (url) {
				var jsonp = eval(decodeURIComponent(url.match(/jsonp=(.*)&property/)[1]));

				jsonp({
					ads: {
						bidId1: {
							cpm: 1,
							html: '<script></script>',
							width: 300,
							height: 600
						}
					}
				});
			});

			mantis.callBids(callBidExample);

			sinon.assert.calledTwice(bidmanager.addBidResponse);

			expect(bidmanager.addBidResponse.firstCall.args[0]).to.eql('foo');

			var bid1 = bidmanager.addBidResponse.firstCall.args[1];
			expect(bid1.getStatusCode()).to.eql(constants.STATUS.GOOD);
			expect(bid1.bidderCode).to.eql('mantis');
			expect(bid1.cpm).to.eql(1);
			expect(bid1.ad).to.eql('<script></script>');
			expect(bid1.width).to.eql(300);
			expect(bid1.height).to.eql(600);

			expect(bidmanager.addBidResponse.secondCall.args[0]).to.eql('bar');

			var bid2 = bidmanager.addBidResponse.secondCall.args[1];
			expect(bid2.getStatusCode()).to.eql(constants.STATUS.NO_BID);
			expect(bid2.bidderCode).to.eql('mantis');
		});

		it('should load script with relevant bid data', () => {
			sandbox.stub(adloader, 'loadScript');

			mantis.callBids(callBidExample);

			sinon.assert.calledOnce(adloader.loadScript);

			var serverCall = adloader.loadScript.firstCall.args[0];

			expect(serverCall).to.match(/buster=[0-9]+&/);
			expect(serverCall).to.match(/tz=-?[0-9]+&/);
			expect(serverCall).to.match(/secure=(true|false)&/);
			expect(serverCall).to.string('property=1234&');
			expect(serverCall).to.string('bids[0][bidId]=bidId1&');
			expect(serverCall).to.string('bids[0][sizes][0][width]=728&');
			expect(serverCall).to.string('bids[0][sizes][0][height]=90&');
			expect(serverCall).to.string('bids[1][bidId]=bidId2&');
			expect(serverCall).to.string('bids[1][sizes][0][width]=300&');
			expect(serverCall).to.string('bids[1][sizes][0][height]=600&');
			expect(serverCall).to.string('bids[1][sizes][1][width]=300&');
			expect(serverCall).to.string('bids[1][sizes][1][height]=250&');
			expect(serverCall).to.string('version=1');
		});

		/* tests below are to just adhere to code coverage requirements, but it is already tested in our own libraries/deployment process */
		it('should send uuid from window if set', () => {
			sandbox.stub(adloader, 'loadScript');

			window.mantis_uuid = '4321';

			mantis.callBids(callBidExample);

			sinon.assert.calledOnce(adloader.loadScript);

			var serverCall = adloader.loadScript.firstCall.args[0];

			expect(serverCall).to.string('uuid=4321&');
		});

		it('should send mobile = true if breakpoint is hit', () => {
			sandbox.stub(adloader, 'loadScript');

			window.mantis_link = true; // causes iframe detection to not work
			window.mantis_breakpoint = 100000000; // force everything to be mobile

			mantis.callBids(callBidExample);

			sinon.assert.calledOnce(adloader.loadScript);

			var serverCall = adloader.loadScript.firstCall.args[0];

			expect(serverCall).to.string('mobile=true&');
		});

		it('should send different params if amp is detected', () => {
			sandbox.stub(adloader, 'loadScript');

			window.context = {
				tagName: "AMP-AD",
				location: {
					href: 'bar',
					referrer: 'baz'
				}
			};

			mantis.callBids(callBidExample);

			sinon.assert.calledOnce(adloader.loadScript);

			var serverCall = adloader.loadScript.firstCall.args[0];

			expect(serverCall).to.string('mobile=true&');
			expect(serverCall).to.string('url=bar&');
		});
	});
});

<|endoftext|>


<commit_before>var _ = require("lodash"),
    Sequelize = require("sequelize"),
    SequelizeG = require("./index.js"),
    assert = require("assert"),
    when = require("when");

var sequelize = new Sequelize("myapp_test",
    "travis",
    "", {
        dialect: "mysql",
        logging: false
    });

describe("Sequelize generator", function () {
    "use strict";

    afterEach(function () {
        // Undo the model definition or it hangs on the sequelize object, infecting
        // subsequent tests
        var daoNames = _.pluck(sequelize.daoFactoryManager.daos, "name");

        daoNames.forEach(function (daoName) {
            sequelize.daoFactoryManager.removeDAO(sequelize.daoFactoryManager.getDAO(daoName));
        });
    });

    var sync = function () {
        return sequelize.getQueryInterface().dropAllTables().then(function () {
            return sequelize.sync({
                force: true
            });
        });
    };

    it("should instantiate a model without relationships", function (done) {
        var ModelWithoutRelationship = sequelize.define("modelWithoutRelationship", {});

        sync().then(function () {
            return new SequelizeG(ModelWithoutRelationship).then(function (modelChild) {
                assert.ok(modelChild.daoFactoryName === ModelWithoutRelationship.name);
            });
        }).then(done, done);
    });

    it("should instantiate a child model and automatically the parent it belongs to", function (done) {
        var ModelParent = sequelize.define("ModelParent", {}),
            ModelChild = sequelize.define("ModelChild", {});

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                assert.ok(parent.daoFactoryName === ModelParent.name);
            });
        }).then(done, done);
    });

    it("should instantiate a child model and automatically the multiple parents it belongs to", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            parentModels = new Array(10),
            parentModelsLength = parentModels.length;

        for (var i = 0; i < parentModelsLength; i++) {
            var ModelParent = sequelize.define("ModelParent" + i, {});

            parentModels[i] = ModelParent;

            ModelChild.belongsTo(ModelParent);
        }

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return when.all(parentModels.map(function (ParentModel, i) {
                    return child["getModelParent" + i]().then(function (parentI) {
                        assert.ok(parentI.daoFactoryName === parentModels[i].name);

                        return i; // Used as a counter on the length assert below
                    });
                }));
            });
        }).then(function (is) {
            assert.equal(parentModelsLength, is.length);
            done();
        }, done);
    });

    it("should instantiate a child model, its parent, and its grandparent", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {}),
            ModelGrandParent = sequelize.define("ModelGrandParent", {});

        ModelChild.belongsTo(ModelParent);
        ModelParent.belongsTo(ModelGrandParent);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent().then(function (parent) {
                    assert.ok(parent.daoFactoryName === ModelParent.name);

                    return parent;
                });
            }).then(function (parent) {
                return parent.getModelGrandParent().then(function (grandParent) {
                    assert.ok(grandParent.daoFactoryName === ModelGrandParent.name);
                });
            });
        }).then(done, done);
    });

    it("should instantiate a child model, and several of its ancestor generations", function (done) {
        var modelsGenerations = [sequelize.define("Model0", {})],
            additionalModelsNumber = 9;

        for (var i = 1; i < additionalModelsNumber + 1; i++) {
            var Model = sequelize.define("Model" + i, {}),
                previousModel = modelsGenerations[i - 1];

            modelsGenerations[i] = Model;

            previousModel.belongsTo(Model);
        }

        sync().then(function () {
            return new SequelizeG(modelsGenerations[0]).then(function (model0) {
                return when.reduce(modelsGenerations, function (currentResult, value, index, total) {
                    if (index < total - 1) {
                        assert.ok(currentResult.daoFactoryName === value.name);
                        return currentResult["getModel" + (index + 1)]();
                    } else {
                        return total;
                    }
                }, model0);
            });
        }).then(function (total) {
            assert.equal(additionalModelsNumber + 1, total);
            done();
        }, done);
    });

    it("should instantiate a child model, both parents, and 4 grandparents (paternal and maternal)", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelFather = sequelize.define("ModelFather", {}),
            ModelMother = sequelize.define("ModelMother", {}),
            ModelPaternalGrandFather = sequelize.define("ModelPaternalGrandFather", {}),
            ModelPaternalGrandMother = sequelize.define("ModelPaternalGrandMother", {}),
            ModelMaternalGrandFather = sequelize.define("ModelMaternalGrandFather", {}),
            ModelMaternalGrandMother = sequelize.define("ModelMaternalGrandMother", {});

        ModelChild.belongsTo(ModelFather);
        ModelChild.belongsTo(ModelMother);

        ModelFather.belongsTo(ModelPaternalGrandFather);
        ModelFather.belongsTo(ModelPaternalGrandMother);

        ModelMother.belongsTo(ModelMaternalGrandFather);
        ModelMother.belongsTo(ModelMaternalGrandMother);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                // Check father and paternal grandparents
                return child.getModelFather().then(function (father) {
                    assert.ok(father.daoFactoryName === ModelFather.name);
                    return father.getModelPaternalGrandFather().then(function (paternalGrandFather) {
                        assert.ok(paternalGrandFather.daoFactoryName === ModelPaternalGrandFather.name);

                        return father.getModelPaternalGrandMother();
                    }).then(function (paternalGrandMother) {
                        assert.ok(paternalGrandMother.daoFactoryName === ModelPaternalGrandMother.name);

                        return child;
                    });
                }).then(function (child) {
                    // Check mother and maternal grandparents
                    return child.getModelMother().then(function (mother) {
                        assert.ok(mother.daoFactoryName === ModelMother.name);
                        return mother.getModelMaternalGrandFather().then(function (maternalGrandFather) {
                            assert.ok(maternalGrandFather.daoFactoryName === ModelMaternalGrandFather.name);

                            return mother.getModelMaternalGrandMother();
                        }).then(function (maternalGrandMother) {
                            assert.ok(maternalGrandMother.daoFactoryName === ModelMaternalGrandMother.name);

                            return null;
                        });
                    });
                });
            });
        }).then(done, done);
    });

    it("should set attributes for Model", function (done) {
        var Model = sequelize.define("Model", {
            name: Sequelize.STRING,
        });

        sync().then(function () {
            return new SequelizeG(Model, {
                attributes: {
                    name: "Julio Nobrega Netto"
                }
            }).then(function (child) {
                assert.equal(child.name, "Julio Nobrega Netto");
            });
        }).then(done, done);
    });

    it("should set attributes for parent model", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {
                name: Sequelize.STRING,
            });

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild, {
                ModelParent: {
                    attributes: {
                        name: "José Nobrega Netto"
                    }
                }
            }).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                assert.equal(parent.name, "José Nobrega Netto");
            });
        }).then(done, done);
    });

    it("should set attributes for grandparent model", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {}),
            ModelGrandParent = sequelize.define("ModelGrandParent", {
                name: Sequelize.STRING,
            });

        ModelChild.belongsTo(ModelParent);
        ModelParent.belongsTo(ModelGrandParent);

        sync().then(function () {
            return new SequelizeG(ModelChild, {
                ModelGrandParent: {
                    attributes: {
                        name: "Julio Nobrega" // notice the lack of Netto
                    }
                }
            }).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                return parent.getModelGrandParent();
            }).then(function (grandParent) {
                assert.equal(grandParent.name, "Julio Nobrega");
            });
        }).then(done, done);
    });

    it("should populate INTEGER data type fields with integers on child model", function (done) {
        var Model = sequelize.define("Model", {
            number: Sequelize.INTEGER
        });

        sync().then(function () {
            return new SequelizeG(Model).then(function (instance) {
                assert.ok(_.isNumber(instance.number));
            });
        }).then(done, done);
    });

    it("should populate INTEGER data type fields with integers on parent models", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {
                number: Sequelize.INTEGER
            });

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                assert.ok(_.isNumber(parent.number));
            });
        }).then(done, done);
    });

    it("should not populate INTEGER data type field on child and parents if set as attributes", function (done) {
        var childNumber = _.uniqueId(),
            parentNumber = _.uniqueId(),
            ModelChild = sequelize.define("ModelChild", {
                number: Sequelize.INTEGER
            }),
            ModelParent = sequelize.define("ModelParent", {
                number: Sequelize.INTEGER
            });

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild, {
                attributes: {
                    number: childNumber
                },
                ModelParent: {
                    attributes: {
                        number: parentNumber
                    }
                }
            }).then(function (child) {
                assert.equal(child.number, childNumber);
                return child.getModelParent();
            }).then(function (parent) {
                assert.equal(parent.number, parentNumber);
            });
        }).then(done, done);
    });

    it("should populate fields when the column is specified as an object", function (done) {
        var Model = sequelize.define("Model", {
            number1: Sequelize.INTEGER,
            number2: {
                type: Sequelize.INTEGER
            }
        });

        sync().then(function () {
            return new SequelizeG(Model).then(function (model) {
                assert.ok(_.isNumber(model.number1));
                assert.ok(_.isNumber(model.number2));
            });
        }).then(done, done);
    });

    it("should populate field with null if specified as an attribute", function (done) {
        var Model = sequelize.define("Model", {
            number: Sequelize.INTEGER
        });

        sync().then(function () {
            return new SequelizeG(Model, {
                attributes: {
                    number: null
                }
            }).then(function (model) {
                assert.ok(_.isNull(model.number));
            });
        }).then(done, done);
    });

    it("should accept as an attribute a foreign key of an already created instance", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return ModelParent.create();
        }).then(function (parent) {
            return new SequelizeG(ModelChild, {
                attributes: {
                    ModelParentId: parent.id
                }
            }).then(function (child) {
                assert.equal(parent.id, child.ModelParentId);
            });
        }).then(done, done);
    });

    it("should set a foreign key to a random, already created record, if option is set", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            var chainer = new Sequelize.Utils.QueryChainer();

            _.times(3, function () {
                chainer.add(ModelParent.create());
            });

            return chainer.run();
        }).then(function (parents) {
            var parentIds = _.pluck(parents, "id");

            return new SequelizeG(ModelChild, {
                ModelParent: "any"
            }).then(function (child) {
                assert.ok(_.contains(parentIds, child.ModelParentId));
            });
        }).then(done, done);
    });

    it("should create record with NULL on fields that reference parents when foreignKeyConstraint is true", function (done) {
        // Only the creation gets NULL. SequelizeG later calls instance.setModelParent(parentInstance) which will
        // replace NULL by parentInstance primary key
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent, {
            foreignKeyConstraint: true
        });

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent().then(function (parent) {
                    assert.ok(child.ModelParentId === parent.id);
                    assert.ok(parent.daoFactoryName === ModelParent.name);
                });
            });
        }).then(done, done);
    });

    it("should populate ENUM data type fields with any value from its possible values", function (done) {
        var possibleValues = ["Julio", "José"],
            Model = sequelize.define("Model", {
                name: {
                    type: Sequelize.ENUM,
                    values: possibleValues
                }
            });

        sync().then(function () {
            return new SequelizeG(Model).then(function (instance) {
                assert.ok(_.contains(possibleValues, instance.name));
            });
        }).then(done, done);
    });

    it("should populate STRING data type fields with random string", function (done) {
        var Model = sequelize.define("Model", {
            name: Sequelize.STRING
        });

        sync().then(function () {
            return new SequelizeG(Model).then(function (instance) {
                assert.ok(_.isString(instance.name));
                assert.ok(instance.name.length > 0);
            });
        }).then(done, done);
    });

    it("should populate STRING(n) data type fields with random string", function (done) {
        var Model = sequelize.define("Model", {
            name: Sequelize.STRING(42)
        });

        sync().then(function () {
            return new SequelizeG(Model).then(function (instance) {
                assert.ok(_.isString(instance.name));
                assert.ok(instance.name.length > 0);
            });
        }).then(done, done);
    });

    it("should set parent model when association has \"as\" option", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent, {
            foreignKey: "ModelParentId",
            as: "someName"
        });

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getSomeName();
            }).then(function (parent) {
                assert.ok(parent.daoFactoryName === ModelParent.name);
            });
        }).then(done, done);
    });

    it("should set parent and grandparent model when associations have \"as\" option", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {}),
            ModelGrandParent = sequelize.define("ModelGrandParent", {});

        ModelChild.belongsTo(ModelParent, {
            foreignKey: "ModelParentId",
            as: "someName"
        });

        ModelParent.belongsTo(ModelGrandParent, {
            foreignKey: "ModelGrandParentId",
            as: "someOtherName"
        });

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getSomeName();
            }).then(function (parent) {
                return parent.getSomeOtherName();
            }).then(function (grandParent) {
                assert.ok(grandParent.daoFactoryName === ModelGrandParent.name);
            }).then(done, done);
        });
    });
});
<commit_msg>Added test to make sure children instances are not created<commit_after>var _ = require("lodash"),
    Sequelize = require("sequelize"),
    SequelizeG = require("./index.js"),
    assert = require("assert"),
    when = require("when");

var sequelize = new Sequelize("myapp_test",
    "travis",
    "", {
        dialect: "mysql",
        logging: false
    });

describe("Sequelize generator", function () {
    "use strict";

    afterEach(function () {
        // Undo the model definition or it hangs on the sequelize object, infecting
        // subsequent tests
        var daoNames = _.pluck(sequelize.daoFactoryManager.daos, "name");

        daoNames.forEach(function (daoName) {
            sequelize.daoFactoryManager.removeDAO(sequelize.daoFactoryManager.getDAO(daoName));
        });
    });

    var sync = function () {
        return sequelize.getQueryInterface().dropAllTables().then(function () {
            return sequelize.sync({
                force: true
            });
        });
    };

    it("should instantiate a model without relationships", function (done) {
        var ModelWithoutRelationship = sequelize.define("modelWithoutRelationship", {});

        sync().then(function () {
            return new SequelizeG(ModelWithoutRelationship).then(function (modelChild) {
                assert.ok(modelChild.daoFactoryName === ModelWithoutRelationship.name);
            });
        }).then(done, done);
    });

    it("should instantiate a child model and automatically the parent it belongs to", function (done) {
        var ModelParent = sequelize.define("ModelParent", {}),
            ModelChild = sequelize.define("ModelChild", {});

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                assert.ok(parent.daoFactoryName === ModelParent.name);
            });
        }).then(done, done);
    });

    it("should instantiate a child model and automatically the multiple parents it belongs to", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            parentModels = new Array(10),
            parentModelsLength = parentModels.length;

        for (var i = 0; i < parentModelsLength; i++) {
            var ModelParent = sequelize.define("ModelParent" + i, {});

            parentModels[i] = ModelParent;

            ModelChild.belongsTo(ModelParent);
        }

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return when.all(parentModels.map(function (ParentModel, i) {
                    return child["getModelParent" + i]().then(function (parentI) {
                        assert.ok(parentI.daoFactoryName === parentModels[i].name);

                        return i; // Used as a counter on the length assert below
                    });
                }));
            });
        }).then(function (is) {
            assert.equal(parentModelsLength, is.length);
            done();
        }, done);
    });

    it("should instantiate a child model, its parent, and its grandparent", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {}),
            ModelGrandParent = sequelize.define("ModelGrandParent", {});

        ModelChild.belongsTo(ModelParent);
        ModelParent.belongsTo(ModelGrandParent);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent().then(function (parent) {
                    assert.ok(parent.daoFactoryName === ModelParent.name);

                    return parent;
                });
            }).then(function (parent) {
                return parent.getModelGrandParent().then(function (grandParent) {
                    assert.ok(grandParent.daoFactoryName === ModelGrandParent.name);
                });
            });
        }).then(done, done);
    });

    it("should instantiate a child model, and several of its ancestor generations", function (done) {
        var modelsGenerations = [sequelize.define("Model0", {})],
            additionalModelsNumber = 9;

        for (var i = 1; i < additionalModelsNumber + 1; i++) {
            var Model = sequelize.define("Model" + i, {}),
                previousModel = modelsGenerations[i - 1];

            modelsGenerations[i] = Model;

            previousModel.belongsTo(Model);
        }

        sync().then(function () {
            return new SequelizeG(modelsGenerations[0]).then(function (model0) {
                return when.reduce(modelsGenerations, function (currentResult, value, index, total) {
                    if (index < total - 1) {
                        assert.ok(currentResult.daoFactoryName === value.name);
                        return currentResult["getModel" + (index + 1)]();
                    } else {
                        return total;
                    }
                }, model0);
            });
        }).then(function (total) {
            assert.equal(additionalModelsNumber + 1, total);
            done();
        }, done);
    });

    it("should instantiate a child model, both parents, and 4 grandparents (paternal and maternal)", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelFather = sequelize.define("ModelFather", {}),
            ModelMother = sequelize.define("ModelMother", {}),
            ModelPaternalGrandFather = sequelize.define("ModelPaternalGrandFather", {}),
            ModelPaternalGrandMother = sequelize.define("ModelPaternalGrandMother", {}),
            ModelMaternalGrandFather = sequelize.define("ModelMaternalGrandFather", {}),
            ModelMaternalGrandMother = sequelize.define("ModelMaternalGrandMother", {});

        ModelChild.belongsTo(ModelFather);
        ModelChild.belongsTo(ModelMother);

        ModelFather.belongsTo(ModelPaternalGrandFather);
        ModelFather.belongsTo(ModelPaternalGrandMother);

        ModelMother.belongsTo(ModelMaternalGrandFather);
        ModelMother.belongsTo(ModelMaternalGrandMother);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                // Check father and paternal grandparents
                return child.getModelFather().then(function (father) {
                    assert.ok(father.daoFactoryName === ModelFather.name);
                    return father.getModelPaternalGrandFather().then(function (paternalGrandFather) {
                        assert.ok(paternalGrandFather.daoFactoryName === ModelPaternalGrandFather.name);

                        return father.getModelPaternalGrandMother();
                    }).then(function (paternalGrandMother) {
                        assert.ok(paternalGrandMother.daoFactoryName === ModelPaternalGrandMother.name);

                        return child;
                    });
                }).then(function (child) {
                    // Check mother and maternal grandparents
                    return child.getModelMother().then(function (mother) {
                        assert.ok(mother.daoFactoryName === ModelMother.name);
                        return mother.getModelMaternalGrandFather().then(function (maternalGrandFather) {
                            assert.ok(maternalGrandFather.daoFactoryName === ModelMaternalGrandFather.name);

                            return mother.getModelMaternalGrandMother();
                        }).then(function (maternalGrandMother) {
                            assert.ok(maternalGrandMother.daoFactoryName === ModelMaternalGrandMother.name);

                            return null;
                        });
                    });
                });
            });
        }).then(done, done);
    });

    it("should set attributes for Model", function (done) {
        var Model = sequelize.define("Model", {
            name: Sequelize.STRING,
        });

        sync().then(function () {
            return new SequelizeG(Model, {
                attributes: {
                    name: "Julio Nobrega Netto"
                }
            }).then(function (child) {
                assert.equal(child.name, "Julio Nobrega Netto");
            });
        }).then(done, done);
    });

    it("should set attributes for parent model", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {
                name: Sequelize.STRING,
            });

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild, {
                ModelParent: {
                    attributes: {
                        name: "José Nobrega Netto"
                    }
                }
            }).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                assert.equal(parent.name, "José Nobrega Netto");
            });
        }).then(done, done);
    });

    it("should set attributes for grandparent model", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {}),
            ModelGrandParent = sequelize.define("ModelGrandParent", {
                name: Sequelize.STRING,
            });

        ModelChild.belongsTo(ModelParent);
        ModelParent.belongsTo(ModelGrandParent);

        sync().then(function () {
            return new SequelizeG(ModelChild, {
                ModelGrandParent: {
                    attributes: {
                        name: "Julio Nobrega" // notice the lack of Netto
                    }
                }
            }).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                return parent.getModelGrandParent();
            }).then(function (grandParent) {
                assert.equal(grandParent.name, "Julio Nobrega");
            });
        }).then(done, done);
    });

    it("should populate INTEGER data type fields with integers on child model", function (done) {
        var Model = sequelize.define("Model", {
            number: Sequelize.INTEGER
        });

        sync().then(function () {
            return new SequelizeG(Model).then(function (instance) {
                assert.ok(_.isNumber(instance.number));
            });
        }).then(done, done);
    });

    it("should populate INTEGER data type fields with integers on parent models", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {
                number: Sequelize.INTEGER
            });

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                assert.ok(_.isNumber(parent.number));
            });
        }).then(done, done);
    });

    it("should not populate INTEGER data type field on child and parents if set as attributes", function (done) {
        var childNumber = _.uniqueId(),
            parentNumber = _.uniqueId(),
            ModelChild = sequelize.define("ModelChild", {
                number: Sequelize.INTEGER
            }),
            ModelParent = sequelize.define("ModelParent", {
                number: Sequelize.INTEGER
            });

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild, {
                attributes: {
                    number: childNumber
                },
                ModelParent: {
                    attributes: {
                        number: parentNumber
                    }
                }
            }).then(function (child) {
                assert.equal(child.number, childNumber);
                return child.getModelParent();
            }).then(function (parent) {
                assert.equal(parent.number, parentNumber);
            });
        }).then(done, done);
    });

    it("should populate fields when the column is specified as an object", function (done) {
        var Model = sequelize.define("Model", {
            number1: Sequelize.INTEGER,
            number2: {
                type: Sequelize.INTEGER
            }
        });

        sync().then(function () {
            return new SequelizeG(Model).then(function (model) {
                assert.ok(_.isNumber(model.number1));
                assert.ok(_.isNumber(model.number2));
            });
        }).then(done, done);
    });

    it("should populate field with null if specified as an attribute", function (done) {
        var Model = sequelize.define("Model", {
            number: Sequelize.INTEGER
        });

        sync().then(function () {
            return new SequelizeG(Model, {
                attributes: {
                    number: null
                }
            }).then(function (model) {
                assert.ok(_.isNull(model.number));
            });
        }).then(done, done);
    });

    it("should accept as an attribute a foreign key of an already created instance", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return ModelParent.create();
        }).then(function (parent) {
            return new SequelizeG(ModelChild, {
                attributes: {
                    ModelParentId: parent.id
                }
            }).then(function (child) {
                assert.equal(parent.id, child.ModelParentId);
            });
        }).then(done, done);
    });

    it("should set a foreign key to a random, already created record, if option is set", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            var chainer = new Sequelize.Utils.QueryChainer();

            _.times(3, function () {
                chainer.add(ModelParent.create());
            });

            return chainer.run();
        }).then(function (parents) {
            var parentIds = _.pluck(parents, "id");

            return new SequelizeG(ModelChild, {
                ModelParent: "any"
            }).then(function (child) {
                assert.ok(_.contains(parentIds, child.ModelParentId));
            });
        }).then(done, done);
    });

    it("should create record with NULL on fields that reference parents when foreignKeyConstraint is true", function (done) {
        // Only the creation gets NULL. SequelizeG later calls instance.setModelParent(parentInstance) which will
        // replace NULL by parentInstance primary key
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent, {
            foreignKeyConstraint: true
        });

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent().then(function (parent) {
                    assert.ok(child.ModelParentId === parent.id);
                    assert.ok(parent.daoFactoryName === ModelParent.name);
                });
            });
        }).then(done, done);
    });

    it("should populate ENUM data type fields with any value from its possible values", function (done) {
        var possibleValues = ["Julio", "José"],
            Model = sequelize.define("Model", {
                name: {
                    type: Sequelize.ENUM,
                    values: possibleValues
                }
            });

        sync().then(function () {
            return new SequelizeG(Model).then(function (instance) {
                assert.ok(_.contains(possibleValues, instance.name));
            });
        }).then(done, done);
    });

    it("should populate STRING data type fields with random string", function (done) {
        var Model = sequelize.define("Model", {
            name: Sequelize.STRING
        });

        sync().then(function () {
            return new SequelizeG(Model).then(function (instance) {
                assert.ok(_.isString(instance.name));
                assert.ok(instance.name.length > 0);
            });
        }).then(done, done);
    });

    it("should populate STRING(n) data type fields with random string", function (done) {
        var Model = sequelize.define("Model", {
            name: Sequelize.STRING(42)
        });

        sync().then(function () {
            return new SequelizeG(Model).then(function (instance) {
                assert.ok(_.isString(instance.name));
                assert.ok(instance.name.length > 0);
            });
        }).then(done, done);
    });

    it("should set parent model when association has \"as\" option", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent, {
            foreignKey: "ModelParentId",
            as: "someName"
        });

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getSomeName();
            }).then(function (parent) {
                assert.ok(parent.daoFactoryName === ModelParent.name);
            });
        }).then(done, done);
    });

    it("should set parent and grandparent model when associations have \"as\" option", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {}),
            ModelGrandParent = sequelize.define("ModelGrandParent", {});

        ModelChild.belongsTo(ModelParent, {
            foreignKey: "ModelParentId",
            as: "someName"
        });

        ModelParent.belongsTo(ModelGrandParent, {
            foreignKey: "ModelGrandParentId",
            as: "someOtherName"
        });

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getSomeName();
            }).then(function (parent) {
                return parent.getSomeOtherName();
            }).then(function (grandParent) {
                assert.ok(grandParent.daoFactoryName === ModelGrandParent.name);
            }).then(done, done);
        });
    });

    it("should only create parents, not children", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {}),
            ModelGrandParent = sequelize.define("ModelGrandParent", {});

        ModelChild.belongsTo(ModelParent);

        ModelParent.belongsTo(ModelGrandParent);

        sync().then(function () {
            return new SequelizeG(ModelParent).then(function (parent) {
                return ModelGrandParent.count();
            }).then(function (grandParentCount) {
                assert.equal(grandParentCount, 1);
            }).then(function () {
                return ModelChild.count();
            }).then(function (childrenCount) {
                assert.equal(childrenCount, 0);
            }).then(done, done);
        });
    });
});
<|endoftext|>