text: /* global appendChartID, loadDateFixture, makeDate */
  describe('dc.lineChart', function () {
      var id, chart, data;
      var dimension, group;
  
      beforeEach(function () {
          data = crossfilter(loadDateFixture());
          dimension = data.dimension(function (d) { return d3.time.day.utc(d.dd); });
          group = dimension.group();
  
          id = 'line-chart';
          appendChartID(id);
  
          chart = dc.lineChart('#' + id);
          chart.dimension(dimension).group(group)
              .width(1100).height(200)
              .x(d3.time.scale.utc().domain([makeDate(2012, 1, 1), makeDate(2012, 11, 31)]))
              .transitionDuration(0);
      });
  
      describe('rendering', function () {
          beforeEach(function () {
              chart.render();
          });
  
          describe('with a specified dash style', function () {
              beforeEach(function () {
                  chart.dashStyle([3, 1, 1, 1]).render();
              });
  
              it('should be dash-dot-dot-dot to match the specified style', function () {
                  expect(chart.selectAll('path.line').attr('stroke-dasharray')).toEqualIntList('3,1,1,1');
              });
          });
  
          describe('render data markers', function () {
              beforeEach(function () {
                  chart.dotRadius(5)
                      .brushOn(false)
                      .renderDataPoints({}).render();
  
              });
  
              it('should use default options', function () {
                  chart.selectAll('circle.dot').each(function () {
                      var dot = d3.select(this);
                      expect(dot.style('fill-opacity')).toBeWithinDelta(0.8);
                      expect(dot.style('stroke-opacity')).toBeWithinDelta(0.8);
                      expect(dot.attr('r')).toBe('2');
                  });
              });
  
              it('should use supplied options', function () {
                  chart.renderDataPoints({radius: 3, fillOpacity: 1, strokeOpacity: 1})
                      .render();
                  chart.selectAll('circle.dot').each(function () {
                      var dot = d3.select(this);
                      expect(dot.style('fill-opacity')).toBe('1');
                      expect(dot.style('stroke-opacity')).toBe('1');
                      expect(dot.attr('r')).toBe('3');
                  });
              });
  
              it('should change the radius on mousemove', function () {
                  chart.selectAll('circle.dot').each(function () {
                      var dot = d3.select(this);
                      dot.on('mousemove').call(this);
                      expect(dot.attr('r')).toBe('5');
                  });
              });
  
              it('should revert to original radius on mouseout', function () {
                  chart.selectAll('circle.dot').each(function () {
                      var dot = d3.select(this);
                      dot.on('mousemove').call(this);
                      dot.on('mouseout').call(this);
                      expect(dot.attr('r')).toBe('2');
                  });
              });
  
              describe('hiding all data markers', function () {
                  beforeEach(function () {
                      chart.renderDataPoints(false).render();
                  });
  
                  it('should not change the default opacity and radius', function () {
                      chart.selectAll('circle.dot').each(function () {
                          expect(d3.select(this).style('fill-opacity')).toBeWithinDelta(1e-6);
                          expect(d3.select(this).style('stroke-opacity')).toBeWithinDelta(1e-6);
                      });
                  });
  
                  it('should not change showing the data point on mousemove', function () {
                      chart.selectAll('circle.dot').each(function () {
                          var dot = d3.select(this);
                          dot.on('mousemove').call(this);
                          expect(dot.style('fill-opacity')).toBeWithinDelta(0.8);
                          expect(dot.style('stroke-opacity')).toBeWithinDelta(0.8);
                      });
                  });
  
                  it('should not change returning to extremely low opacity on hover out', function () {
                      chart.selectAll('circle.dot').each(function () {
                          var dot = d3.select(this);
                          dot.on('mousemove').call(this);
                          dot.on('mouseout').call(this);
                          expect(dot.style('fill-opacity')).toBeWithinDelta(1e-6);
                          expect(dot.style('stroke-opacity')).toBeWithinDelta(1e-6);
                      });
                  });
              });
          });
  
          describe('title rendering', function () {
              beforeEach(function () {
                  chart.renderTitle(false);
                  chart.render();
              });
  
              it('should not render dots and tips when boolean flag is false', function () {
                  expect(chart.select('.dc-tooltip._0 .dot').empty()).toBeTruthy();
                  expect(chart.select('.dc-tooltip._0 .dot title').empty()).toBeTruthy();
              });
  
          });
  
          describe('title rendering with brushOn', function () {
              beforeEach(function () {
                  chart.brushOn(true)
                      .xyTipsOn(true); // default, for exposition
                  chart.render();
              });
  
              it('should not render tips', function () {
                  expect(chart.select('.dc-tooltip._0 .dot').empty()).toBeTruthy();
                  expect(chart.select('.dc-tooltip._0 .dot title').empty()).toBeTruthy();
              });
  
              describe('with xyTipsOn always', function () {
                  beforeEach(function () {
                      chart.brushOn(true)
                          .xyTipsOn('always');
                      chart.render();
                  });
  
                  it('should render dots', function () {
                      expect(chart.select('.dc-tooltip._0 .dot').empty()).toBeFalsy();
                      expect(chart.select('.dc-tooltip._0 .dot title').empty()).toBeFalsy();
                  });
              });
          });
  
          describe('label rendering off', function () {
              beforeEach(function () {
                  chart.renderLabel(false);
                  chart.render();
              });
  
              it('should produce no labels', function () {
                  expect(chart.selectAll('.lineLabel').empty()).toBeTruthy();
              });
          });
  
          describe('label rendering', function () {
              beforeEach(function () {
                  chart.renderLabel(true);
                  chart.render();
              });
  
              it('should generate a label for each datum', lineLabelCount);
              it('should generate labels with positions corresponding to their data', lineLabelPositions);
          });
  
          describe('data point highlights and refs off', function () {
              beforeEach(function () {
                  chart.title(function (d) { return d.value; });
                  chart.brushOn(false).xyTipsOn(false).render();
              });
              it('should not generate per data points', function () {
                  expect(chart.selectAll('circle.dot').size()).toBe(0);
              });
              it('should not generate x and y refs', function () {
                  expect(chart.selectAll('path.xRef').size()).toBe(0);
                  expect(chart.selectAll('path.yRef').size()).toBe(0);
              });
          });
  
          describe('data point highlights', function () {
              beforeEach(function () {
                  chart.title(function (d) { return d.value; });
                  chart.brushOn(false).dotRadius(10).render();
              });
              it('should not generate a chart brush', function () {
                  expect(chart.selectAll('g.brush').empty()).toBeTruthy();
              });
  
              it('should be generated per data point', function () {
                  expect(chart.selectAll('circle.dot').size()).toBe(6);
              });
  
              it('should have configurable radius', function () {
                  chart.selectAll('circle.dot').each(function () {
                      expect(d3.select(this).attr('r')).toBe('10');
                  });
              });
  
              it('should be have extremely low opacity by default', function () {
                  chart.selectAll('circle.dot').each(function () {
                      expect(d3.select(this).style('fill-opacity')).toBeWithinDelta(1e-6);
                      expect(d3.select(this).style('stroke-opacity')).toBeWithinDelta(1e-6);
                  });
              });
  
              it('should become visible when hovered over', function () {
                  chart.selectAll('circle.dot').each(function () {
                      var dot = d3.select(this);
                      dot.on('mousemove').call(this);
                      expect(dot.style('fill-opacity')).toBeWithinDelta(0.8);
                      expect(dot.style('stroke-opacity')).toBeWithinDelta(0.8);
                  });
              });
  
              it('should return to extremely low opacity on hover out', function () {
                  chart.selectAll('circle.dot').each(function () {
                      var dot = d3.select(this);
                      dot.on('mousemove').call(this);
                      dot.on('mouseout').call(this);
                      expect(dot.style('fill-opacity')).toBeWithinDelta(1e-6);
                      expect(dot.style('stroke-opacity')).toBeWithinDelta(1e-6);
                  });
              });
  
              it('should render titles on to each circle', function () {
                  chart.selectAll('g._0 circle.dot').each(function (d) {
                      expect(+d3.select(this).select('title').text()).toBe(d.data.value);
                  });
              });
  
              describe('ref lines', function () {
                  it('should generate lines that are hidden by default', function () {
                      expect(chart.select('path.xRef').style('display')).toBe('none');
                      expect(chart.select('path.yRef').style('display')).toBe('none');
                  });
  
                  it('should have a stroke dash', function () {
                      expect(chart.selectAll('path.xRef').attr('stroke-dasharray')).toEqualIntList('5,5');
                      expect(chart.selectAll('path.yRef').attr('stroke-dasharray')).toEqualIntList('5,5');
                  });
  
                  describe('when dot is hovered over', function () {
                      describe('for vertical ref lines', function () {
                          var x;
                          beforeEach(function () {
                              var dot = chart.select('circle.dot');
                              dot.on('mousemove').call(dot[0][0]);
                              x = dot.attr('cx');
                          });
  
                          it('shows the ref line from the bottom of the graph', function () {
                              var path = 'M' + x + ' 160 L ' + x + ' 107';
                              expect(chart.select('path.xRef').attr('d')).toMatchPath(path);
                              expect(chart.select('path.xRef').attr('display')).not.toBe('none');
                          });
                      });
  
                      describe('for horizontal ref lines', function () {
                          describe('for a left y-axis chart', function () {
                              var x;
                              beforeEach(function () {
                                  var dot = chart.select('circle.dot');
                                  dot.on('mousemove').call(dot[0][0]);
                                  x = dot.attr('cx');
                              });
  
                              it('shows the ref line on the left', function () {
                                  var path = 'M0 107 L ' + x + ' 107';
                                  expect(chart.select('path.yRef').attr('d')).toMatchPath(path);
                                  expect(chart.select('path.yRef').attr('display')).not.toBe('none');
                              });
                          });
  
                          describe('for a right y-axis chart', function () {
                              var x;
                              beforeEach(function () {
                                  chart.useRightYAxis(true).render();
                                  var dot = chart.select('circle.dot');
                                  dot.on('mousemove').call(dot[0][0]);
                                  x = dot.attr('cx');
                              });
  
                              it('shows the ref line on the right', function () {
                                  var path = 'M1020 107L' + x + ' 107';
                                  expect(chart.select('path.yRef').attr('d')).toMatchPath(path); //"M1020 107L405 107");
                                  expect(chart.select('path.yRef').attr('display')).not.toBe('none');
                              });
                          });
                      });
                  });
              });
          });
  
          describe('undefined points', function () {
              beforeEach(function () {
                  chart.defined(function (d) { return d.x.valueOf() !== makeDate(2012, 5, 10).getTime(); });
                  chart.brushOn(false).render();
              });
  
              it('should not show line where not defined', function () {
                  expect(chart.select('path.line').attr('d').indexOf('M', 1)).not.toBe(-1);
              });
  
              it('should not draw dots on undefined points', function () {
                  expect(chart.selectAll('.dot').size()).toBe(5);
              });
          });
  
          describe('with chart area enabled', function () {
              beforeEach(function () {
                  chart.renderArea(true).render();
              });
  
              it('should draw the chart line', function () {
                  expect(chart.select('path.line').attr('d')).toMatchPath('M348,107 L390,107 L397,0 L461,107 L488,53 L583,53');
              });
  
              it('should draw the chart area', function () {
                  expect(chart.select('path.area').attr('d')).toMatchPath('M348,107 L390,107 L397,0 L461,107 L488,53 L583,' +
                      '53 L583,160 L488,160 L461,160 L397,160 L390,160 L348,160Z');
              });
          });
  
          describe('with an ordinal x domain', function () {
              beforeEach(function () {
                  var stateDimension = data.dimension(function (d) { return d.state; });
                  var stateGroup = stateDimension.group();
  
                  chart.dimension(stateDimension)
                      .group(stateGroup)
                      .xUnits(dc.units.ordinal)
                      .x(d3.scale.ordinal().domain(['California', 'Colorado', 'Delaware', 'Mississippi', 'Oklahoma', 'Ontario']))
                      .render();
              });
  
              it('should automatically disable the brush', function () {
                  expect(chart.brushOn()).toBeFalsy();
              });
  
              it('should generate an ordinal path', function () {
                  expect(chart.select('path.line').attr('d')).toMatchPath('M85,0L255,107L425,107L595,53L765,107L935,53');
              });
          });
  
          describe('with stacked data', function () {
              describe('with positive data', function () {
                  beforeEach(function () {
                      var idGroup = dimension.group().reduceSum(function (d) { return d.id; });
                      var valueGroup = dimension.group().reduceSum(function (d) { return d.value; });
  
                      chart.dimension(dimension)
                          .brushOn(false)
                          .x(d3.time.scale.utc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)]))
                          .group(idGroup, 'stack 0')
                          .title('stack 0', function (d) { return 'stack 0: ' + d.value; })
                          .stack(valueGroup, 'stack 1')
                          .title('stack 1', function (d) { return 'stack 1: ' + d.value; })
                          .stack(valueGroup, 'stack 2')
                          .elasticY(true)
                          .render();
                  });
  
                  it('should render the correct number of lines', function () {
                      expect(chart.selectAll('path.line').size()).toBe(3);
                  });
  
                  it('should set the path for stack 0 line', function () {
                      expect(chart.select('g._0 path.line').attr('d')).toMatchPath('M58 159L222 157L246 150L492 158L597 151L961 153');
                  });
  
                  it('should set the path for stack 1 line', function () {
                      expect(chart.select('g._1 path.line').attr('d')).toMatchPath('M58 134L222 119L246 75L492 133L597 120L961 109');
                  });
  
                  it('should set the path for stack 2 line', function () {
                      expect(chart.select('g._2 path.line').attr('d')).toMatchPath('M58 109L222 81L246 0L492 108L597 89L961 65');
                  });
  
                  it('should have its own title accessor', function () {
                      expect(chart.title()({value: 1})).toBe('stack 0: 1');
                      expect(chart.title('stack 0')({value: 2})).toBe('stack 0: 2');
                      expect(chart.title('stack 1')({value: 3})).toBe('stack 1: 3');
                  });
  
                  it('should have titles rendered for extra stacks', function () {
                      chart.selectAll('g._1 circle.dot').each(function (d) {
                          expect(d3.select(this).select('title').text()).toBe('stack 1: ' + d.data.value);
                      });
                  });
  
                  it('should default to first stack title for untitled stacks', function () {
                      chart.selectAll('g._2 circle.dot').each(function (d) {
                          expect(d3.select(this).select('title').text()).toBe('stack 0: ' + d.data.value);
                      });
                  });
  
                  describe('with chart area enabled', function () {
                      beforeEach(function () {
                          chart.renderArea(true).render();
                      });
  
                      it('should render the correct number of areas', function () {
                          expect(chart.selectAll('path.area').size()).toBe(3);
                      });
  
                      it('should set the area for stack 0', function () {
                          expect(chart.select('g._0 path.area').attr('d')).toMatchPath('M58 159L222 157L246 150L492 158L597 ' +
                              '151L961 153L961 160L597 160L492 160L246 160L222 160L58 160Z');
                      });
  
                      it('should set the area for stack 1', function () {
                          expect(chart.select('g._1 path.area').attr('d')).toMatchPath('M58 134L222 119L246 75L492 133L597 ' +
                              '120L961 109L961 153L597 151L492 158L246 150L222 157L58 159Z');
                      });
  
                      it('should set the area for stack 2', function () {
                          expect(chart.select('g._2 path.area').attr('d')).toMatchPath('M58 109L222 81L246 0L492 108L597 89L961 ' +
                              '65L961 109L597 120L492 133L246 75L222 119L58 134Z');
                      });
  
                      it('should draw tooltip dots on top of paths and areas', function () {
                          var list = chart.selectAll('circle.dot, path.line, path.area');
  
                          var indexOfLastLine = list[0].indexOf(list.filter('path.line')[0][2]);
                          var indexOfLastArea = list[0].indexOf(list.filter('path.area')[0][2]);
                          var indexOfDot = list[0].indexOf(list.filter('circle.dot')[0][0]);
  
                          expect(indexOfDot).toBeGreaterThan(indexOfLastArea);
                          expect(indexOfDot).toBeGreaterThan(indexOfLastLine);
                      });
  
                      it('should draw tooltip ref lines on top of paths', function () {
                          var list = chart.selectAll('path.yRef, path.xRef, path.line, path.area');
  
                          var indexOfLastLine = list[0].indexOf(list.filter('path.line')[0][2]);
                          var indexOfLastArea = list[0].indexOf(list.filter('path.area')[0][2]);
  
                          var indexOfFirstYRef = list[0].indexOf(list.filter('path.yRef')[0][0]);
                          var indexOfFirstXRef = list[0].indexOf(list.filter('path.xRef')[0][0]);
  
                          expect(indexOfLastLine).toBeLessThan(indexOfFirstXRef);
                          expect(indexOfLastLine).toBeLessThan(indexOfFirstYRef);
  
                          expect(indexOfLastArea).toBeLessThan(indexOfFirstXRef);
                          expect(indexOfLastArea).toBeLessThan(indexOfFirstYRef);
                      });
  
                  });
  
                  describe('stack hiding', function () {
                      describe('first stack', function () {
                          beforeEach(function () {
                              chart.hideStack('stack 0').render();
                          });
  
                          it('should hide the stack', function () {
                              expect(chart.select('g._0 path.line').attr('d')).toMatchPath('M58 133L222 120L246 80L492 133L597 127L961 113');
                          });
  
                          it('should show the stack', function () {
                              chart.showStack('stack 0').render();
                              expect(chart.select('g._0 path.line').attr('d')).toMatchPath('M58 159L222 157L246 150L492 158L597 151L961 153');
                          });
                      });
  
                      describe('any other stack', function () {
                          beforeEach(function () {
                              chart.title('stack 2', function (d) { return 'stack 2: ' + d.value; });
                              chart.hideStack('stack 1').render();
                          });
  
                          it('should hide the stack', function () {
                              expect(chart.select('g._1 path.line').attr('d')).toMatchPath('M58 112L222 83L246 0L492 108L597 85L961 64');
                          });
  
                          it('should show the stack', function () {
                              chart.showStack('stack 1').render();
                              expect(chart.select('g._1 path.line').attr('d')).toMatchPath('M58 134L222 119L246 75L492 133L597 120L961 109');
                          });
  
                          it('should color chart dots the same as line paths', function () {
                              var lineColor = chart.select('g._1 path.line').attr('stroke');
                              var circleColor = chart.select('g._1 circle.dot').attr('fill');
                              expect(lineColor).toEqual(circleColor);
                          });
  
                          it('should still show the title for a visible stack', function () {
                              chart.selectAll('g._1 circle.dot').each(function (d) {
                                  expect(d3.select(this).select('title').text()).toBe('stack 2: ' + d.data.value);
                              });
                          });
                      });
  
                      describe('hiding all the stacks', function () {
                          beforeEach(function () {
                              chart.hideStack('stack 0')
                                  .hideStack('stack 1')
                                  .hideStack('stack 2')
                                  .render();
                          });
  
                          it('should show a blank graph', function () {
                              expect(chart.selectAll('path.line').size()).toBe(0);
                          });
                      });
                  });
  
                  describe('label rendering', function () {
                      beforeEach(function () {
                          chart.renderLabel(true);
                          chart.render();
                      });
  
                      it('should generate a label for each datum', lineLabelCount);
                      it('should generate labels with positions corresponding to their data', lineLabelPositions);
                  });
              });
  
              describe('with mixed positive and negative data', function () {
                  beforeEach(function () {
                      var mixedGroup = dimension.group().reduceSum(function (d) { return d.nvalue; });
  
                      chart.group(mixedGroup).stack(mixedGroup).stack(mixedGroup);
                      chart.x(d3.time.scale.utc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)]));
  
                      chart.margins({top: 30, right: 50, bottom: 30, left: 30})
                          .renderArea(true)
                          .yAxisPadding(5)
                          .elasticY(true)
                          .yAxis().ticks(5);
  
                      chart.render();
                  });
  
                  it('should generate a line and area for each stack', function () {
                      expect(chart.selectAll('path.line').size()).toBe(3);
                      expect(chart.selectAll('path.area').size()).toBe(3);
                  });
  
                  it('should generate negative lines and area for stack 0', function () {
                      expect(chart.select('g._0 path.line').attr('d')).toMatchPath('M58 81L222 81L246 92L492 79L597 52L961 67');
                      expect(chart.select('g._0 path.area').attr('d')).toMatchPath('M58 81L222 81L246 92L492 79L597 52L961 ' +
                          '67L961 73L597 73L492 73L246 73L222 73L58 73Z');
                  });
  
                  it('should generate negative lines and area for stack 1', function () {
                      expect(chart.select('g._1 path.line').attr('d')).toMatchPath('M58 88L222 88L246 111L492 84L597 31L961 61');
                      expect(chart.select('g._1 path.area').attr('d')).toMatchPath('M58 88L222 88L246 111L492 84L597 31L961 ' +
                          '61L961 67L597 52L492 79L246 92L222 81L58 81Z');
                  });
  
                  it('should generate y axis domain dynamically', function () {
                      var nthText = function (n) { return d3.select(chart.selectAll('g.axis.y .tick text')[0][n]); };
  
                      expect(nthText(0).text()).toBe('-20');
                      expect(nthText(1).text()).toBe('0');
                      expect(nthText(2).text()).toBe('20');
                  });
  
                  describe('label rendering', function () {
                      beforeEach(function () {
                          chart.renderLabel(true);
                          chart.render();
                      });
  
                      it('should generate a label for each datum', lineLabelCount);
                      it('should generate labels with positions corresponding to their data', lineLabelPositions);
                  });
              });
  
              describe('with negative data', function () {
                  beforeEach(function () {
                      var negativeGroup = dimension.group().reduceSum(function (d) { return -Math.abs(d.nvalue); });
  
                      chart.group(negativeGroup).stack(negativeGroup).stack(negativeGroup);
                      chart.x(d3.time.scale.utc().domain([makeDate(2012, 4, 20), makeDate(2012, 7, 15)]));
  
                      chart.margins({top: 30, right: 50, bottom: 30, left: 30})
                          .elasticY(true)
                          .xUnits(d3.time.days.utc)
                          .yAxis().ticks(3);
  
                      chart.render();
                  });
  
                  it('should generate y axis domain dynamically', function () {
                      var nthText = function (n) { return d3.select(chart.selectAll('g.axis.y .tick text')[0][n]); };
  
                      expect(nthText(0).text()).toBe('-30');
                      expect(nthText(1).text()).toBe('-20');
                      expect(nthText(2).text()).toBe('-10');
                      expect(nthText(3).text()).toBe('0');
                  });
              });
          });
  
          describe('legend hovering', function () {
              var firstItem;
  
              beforeEach(function () {
                  chart.stack(group)
                      .legend(dc.legend().x(400).y(10).itemHeight(13).gap(5))
                      .renderArea(true)
                      .render();
  
                  firstItem = chart.select('g.dc-legend g.dc-legend-item');
                  firstItem.on('mouseover')(firstItem.datum());
              });
  
              describe('when a legend item is hovered over', function () {
                  it('should highlight corresponding lines and areas', function () {
                      expect(nthLine(0).classed('highlight')).toBeTruthy();
                      expect(nthArea(0).classed('highlight')).toBeTruthy();
                  });
  
                  it('should fade out non-corresponding lines and areas', function () {
                      expect(nthLine(1).classed('fadeout')).toBeTruthy();
                      expect(nthArea(1).classed('fadeout')).toBeTruthy();
                  });
              });
  
              describe('when a legend item is hovered out', function () {
                  it('should remove highlighting from corresponding lines and areas', function () {
                      firstItem.on('mouseout')(firstItem.datum());
                      expect(nthLine(0).classed('highlight')).toBeFalsy();
                      expect(nthArea(0).classed('highlight')).toBeFalsy();
                  });
  
                  it('should fade in non-corresponding lines and areas', function () {
                      firstItem.on('mouseout')(firstItem.datum());
                      expect(nthLine(1).classed('fadeout')).toBeFalsy();
                      expect(nthArea(1).classed('fadeout')).toBeFalsy();
                  });
              });
  
              function nthLine (n) {
                  return d3.select(chart.selectAll('path.line')[0][n]);
              }
  
              function nthArea (n) {
                  return d3.select(chart.selectAll('path.area')[0][n]);
              }
          });
  
          describe('filtering', function () {
              beforeEach(function () {
                  chart.filter([makeDate(2012, 5, 1), makeDate(2012, 5, 30)]).redraw();
              });
  
              it('should set the chart filter', function () {
                  expect(chart.filter()).toEqual([makeDate(2012, 5, 1), makeDate(2012, 5, 30)]);
              });
  
              it('should set the filter printer', function () {
                  expect(chart.filterPrinter()).not.toBeNull();
              });
  
              it('should not generate tooltip circles with the default brush', function () {
                  expect(chart.selectAll('circle.dot').empty()).toBeTruthy();
              });
  
              describe('when a brush is defined', function () {
                  it('should position the brush with an offset', function () {
                      expect(chart.select('g.brush').attr('transform')).toMatchTranslate(chart.margins().left, 10);
                  });
  
                  it('should create a fancy brush resize handle', function () {
                      chart.select('g.brush').selectAll('.resize path').each(function (d, i) {
                          if (i === 0) {
                              expect(d3.select(this).attr('d'))
                                  .toMatchPath('M0.5,53 A6,6 0 0 1 6.5,59 V100 A6,6 0 0 1 0.5,106 ZM2.5,61 V98 M4.5,61 V98');
                          } else {
                              expect(d3.select(this).attr('d'))
                                  .toMatchPath('M-0.5,53 A6,6 0 0 0 -6.5,59 V100 A6,6 0 0 0 -0.5,106 ZM-2.5,61 V98 M-4.5,61 V98');
                          }
                      });
                  });
  
                  it('should stretch the background', function () {
                      expect(chart.select('g.brush rect.background').attr('width')).toBe('1020');
                  });
  
                  it('should set the background height to the chart height', function () {
                      expect(chart.select('g.brush rect.background').attr('height')).toBe('160');
                  });
  
                  it('should set extent height to the chart height', function () {
                      expect(chart.select('g.brush rect.extent').attr('height')).toBe('160');
                  });
  
                  it('should set extent width based on filter set', function () {
                      expect(chart.select('g.brush rect.extent').attr('width')).toBeWithinDelta(88, 1);
                  });
  
                  it('should not have an area path', function () {
                      expect(chart.selectAll('path.area').empty()).toBeTruthy();
                  });
  
                  it('should set the dash style to solid', function () {
                      expect(chart.selectAll('path.line').attr('stroke-dasharray')).toBeNull();
                  });
              });
          });
          describe('changing data', function () {
              var stateDimension;
              beforeEach(function () {
                  chart.brushOn(false)
                      .title(function (d) { return d.value; })
                      .render();
                  stateDimension = data.dimension(function (d) { return d.state; });
                  stateDimension.filter('CA');
                  chart.redraw();
              });
  
              it('should update dot titles', function () {
                  chart.selectAll('g._0 circle.dot').each(function (d) {
                      expect(d3.select(this).select('title').size()).toBe(1);
                      expect(+d3.select(this).select('title').text()).toBe(d.data.value);
                  });
              });
  
              afterEach(function () {
                  stateDimension.filter(null);
              });
          });
      });
      describe('change color', function () {
          beforeEach(function () {
              chart.brushOn(false)
                  .ordinalColors(['#ff0000'])
                  .colorAccessor(function () { return 0; })
                  .render();
          });
          it('updates dot colors', function () {
              expect(chart.select('circle.dot')[0][0].attributes.fill.value).toMatch(/#ff0000/i);
          });
      });
  
      function lineLabelCount () {
          expect(chart.selectAll('text.lineLabel').size()).toBe(chart.stack().length * chart.group().all().length);
      }
  
      function lineLabelPositions () {
          var LABEL_PADDING = 3;
          chart.selectAll('.stack')[0].forEach(function (stack, i) {
              d3.select(stack).selectAll('text.lineLabel')[0].forEach(function (lineLabel, j) {
                  expect(+d3.select(lineLabel).attr('x')).toBeCloseTo(chart.x()(chart.data()[i].values[j].x));
                  expect(+d3.select(lineLabel).attr('y') + LABEL_PADDING).toBeCloseTo(chart.y()(chart.data()[i].values[j].y +
                          chart.data()[i].values[j].y0));
              });
          });
      }
  });
  