import { d3, c3, initChart } from './c3-helper'

describe('c3 chart axis', function() {
  'use strict'

  var chart

  var args: any = {
    data: {
      columns: [
        ['data1', 30, 200, 100, 400, 150, 250],
        ['data2', 50, 20, 10, 40, 15, 25],
        ['data3', 150, 120, 110, 140, 115, 125]
      ]
    },
    axis: {
      y: {
        tick: {
          values: null,
          count: undefined
        }
      },
      y2: {
        tick: {
          values: null,
          count: undefined
        }
      }
    }
  }

  beforeEach(function(done) {
    chart = initChart(chart, args, done)
  })

  describe('axis.y.tick.count', function() {
    describe('with only 1 tick on y axis', function() {
      beforeAll(function() {
        args.axis.y.tick.count = 1
      })

      it('should have only 1 tick on y axis', function() {
        var ticksSize = d3
          .select('.c3-axis-y')
          .selectAll('g.tick')
          .size()
        expect(ticksSize).toBe(1)
      })
    })

    describe('with 2 ticks on y axis', function() {
      beforeAll(function() {
        args.axis.y.tick.count = 2
      })

      it('should have 2 ticks on y axis', function() {
        var ticksSize = d3
          .select('.c3-axis-y')
          .selectAll('g.tick')
          .size()
        expect(ticksSize).toBe(2)
      })
    })

    describe('with 3 ticks on y axis', function() {
      beforeAll(function() {
        args.axis.y.tick.count = 3
      })

      it('should have 3 ticks on y axis', function() {
        var ticksSize = d3
          .select('.c3-axis-y')
          .selectAll('g.tick')
          .size()
        expect(ticksSize).toBe(3)
      })
    })
  })

  describe('axis.y.tick.values', function() {
    var values = [100, 500]

    describe('with only 2 ticks on y axis', function() {
      beforeAll(function() {
        args.axis.y.tick.values = values
      })

      it('should have only 2 tick on y axis', function() {
        var ticksSize = d3
          .select('.c3-axis-y')
          .selectAll('g.tick')
          .size()
        expect(ticksSize).toBe(2)
      })

      it('should have specified tick texts', function() {
        d3.select('.c3-axis-y')
          .selectAll('g.tick')
          .each(function(d, i) {
            var text = d3
              .select(this)
              .select('text')
              .text()
            expect(+text).toBe(values[i])
          })
      })
    })
  })

  describe('axis x timeseries with seconds', function() {
    beforeAll(function() {
      args = {
        data: {
          type: 'line',
          columns: [
            ['epoch', 1401879600000, 1401883200000, 1401886800000],
            ['y', 1955, 2419, 2262]
          ],
          xs: {
            y: 'epoch'
          }
        },
        axis: {
          x: {
            type: 'timeseries',
            min: new Date(1401879600000),
            max: new Date(1401969600000),
            localtime: false
          }
        }
      }
    })

    it('should have 3 ticks on x axis', function() {
      var ticksSize = d3
        .select('.c3-axis-x')
        .selectAll('g.tick')
        .size()
      expect(ticksSize).toBe(3)
    })

    it('should have specified 1 hour intervals', function() {
      var prevValue
      d3.select('.c3-axis-x')
        .selectAll('g.tick')
        .each(function(d: any, i) {
          if (i !== 0) {
            var result = d - prevValue
            expect(result).toEqual(3600000) // expressed in milliseconds
          }
          prevValue = d
        })
    })

    describe('changing min x time and columns', function() {
      beforeAll(function() {
        args.axis.x.min = new Date(1401876000000)
        args.axis.x.max = new Date(1401876075000)
        args.data.columns = [
          [
            'epoch',
            1401876000000,
            1401876015000,
            1401876030000,
            1401876045000,
            1401876060000,
            1401876075000
          ],
          ['y', 1968, 1800, 1955, 2419, 2262, 1940]
        ]
      })

      it('should have 6 ticks on x axis', function() {
        var ticksSize = d3
          .select('.c3-axis-x')
          .selectAll('g.tick')
          .size()
        expect(ticksSize).toBe(6) // the count starts at initial value and increments by the set interval
      })

      it('should have specified 15 seconds intervals', function() {
        var prevValue
        d3.select('.c3-axis-x')
          .selectAll('g.tick')
          .each(function(d: any, i) {
            if (i !== 0) {
              var result = d - prevValue
              expect(result).toEqual(15000) // expressed in milliseconds
            }
            prevValue = d
          })
      })

      describe('with axis.x.time.format %Y-%m-%d %H:%M:%S', function() {
        beforeAll(function() {
          args.axis.x.tick = {
            format: '%M:%S' // https://github.com/mbostock/d3/wiki/Time-Formatting#wiki-format
          }
        })

        var textDates = ['00:00', '00:15', '00:30', '00:45', '01:00', '01:15']

        it('should format x ticks as dates with time', function() {
          var ticks = d3
            .select('.c3-axis-x')
            .selectAll('g.tick')
            .selectAll('tspan')
            .each(function(d: any) {
              expect(d.splitted).toEqual(textDates[d.index])
            })
          expect(ticks.size()).toBe(6)
        })
      })
    })
  })

  describe('axis x timeseries with iso dates', function() {
    beforeAll(function() {
      args = {
        data: {
          type: 'line',
          columns: [
            ['epoch', 1527811200000, 1527897600000, 1527984000000],
            ['y', 1955, 2419, 2262]
          ],
          xs: {
            y: 'epoch'
          }
        },
        axis: {
          x: {
            type: 'timeseries',
            min: new Date('2018-06-01'),
            max: new Date('2018-06-03'),
            localtime: false,
            tick: {
              format: '%Y-%m-%dT%H:%M:%S' // https://github.com/mbostock/d3/wiki/Time-Formatting#wiki-format
            }
          }
        }
      }
    })
    var textDates = [
      '2018-06-01T00:00:00',
      '2018-06-02T00:00:00',
      '2018-06-03T00:00:00'
    ]

    it('should format x ticks as dates', function() {
      var ticks = d3
        .select('.c3-axis-x')
        .selectAll('g.tick')
        .selectAll('tspan')
        .each(function(d: any) {
          expect(d.splitted).toEqual(textDates[d.index])
        })
      expect(ticks.size()).toBe(3)
    })
  })

  describe('axis y timeseries', function() {
    beforeAll(function() {
      args = {
        data: {
          columns: [['times', 60000, 120000, 180000, 240000]]
        },
        axis: {
          y: {
            type: 'timeseries',
            tick: {
              time: {}
            }
          }
        }
      }
    })

    it('should have 7 ticks on y axis', function() {
      var ticksSize = d3
        .select('.c3-axis-y')
        .selectAll('g.tick')
        .size()
      expect(ticksSize).toBe(7) // the count starts at initial value and increments by the set interval
    })

    it('should have specified 30 second intervals', function() {
      var prevValue
      d3.select('.c3-axis-y')
        .selectAll('g.tick')
        .each(function(d: any, i) {
          if (i !== 0) {
            var result = d - prevValue
            expect(result).toEqual(30000) // expressed in milliseconds
          }
          prevValue = d
        })
    })

    describe('with axis.y.time', function() {
      beforeAll(function() {
        args.axis.y.tick.time = {
          type: d3.timeSecond,
          interval: 60
        }
      })

      it('should have 4 ticks on y axis', function() {
        var ticksSize = d3
          .select('.c3-axis-y')
          .selectAll('g.tick')
          .size()
        expect(ticksSize).toBe(4) // the count starts at initial value and increments by the set interval
      })

      it('should have specified 60 second intervals', function() {
        var prevValue
        d3.select('.c3-axis-y')
          .selectAll('g.tick')
          .each(function(d: any, i) {
            if (i !== 0) {
              var result = d - prevValue
              expect(result).toEqual(60000) // expressed in milliseconds
            }
            prevValue = d
          })
      })
    })
  })

  describe('axis.y.type', function() {
    describe('type=log', function() {
      beforeAll(function() {
        args = {
          data: {
            columns: [
              ['linear', 318, 37, 0, 4, 0, 1],
              ['log', 318, 37, 0, 4, 0, 1]
            ],
            type: 'bar',
            axes: {
              log: 'y',
              linear: 'y2'
            },
            labels: true
          },
          axis: {
            y: {
              type: 'log'
            },
            y2: {
              show: true
            }
          }
        }
      })

      it('should have bars from y bigger than y2', function() {
        expect(
          (d3.select('.c3-bars-log .c3-bar-5').node() as any).getBBox().height
        ).toBeGreaterThan(
          (d3.select('.c3-bars-linear .c3-bar-5').node() as any).getBBox()
            .height
        )
      })

      it('should not have truncated data label', () => {
        const text = d3.select('.c3-texts-log .c3-text-0').node() as any

        expect(text).not.toBeUndefined()

        const bbox = text.getBBox()

        expect(Math.abs(bbox.y) - bbox.height).toBeGreaterThan(0)
      })
    })
  })

  describe('axis.x.tick.values', function() {
    describe('formatted correctly when negative', function() {
      var xValues = [-3.3, -2.2, -1.1, 1.1, 2.2, 3.3]
      beforeEach(function() {
        args.data = {
          x: 'x',
          columns: [
            ['x'].concat(xValues as any),
            ['data1', 30, 200, 100, 400, 150, 250]
          ]
        }
      })

      it('should not generate whole number for negative values', function() {
        var tickValues = []
        d3.select('.c3-axis-x')
          .selectAll('g.tick')
          .selectAll('tspan')
          .each(function(d: any, i) {
            expect(tickValues.push(parseFloat(d.splitted)) === xValues[i])
          })
      })
    })

    describe('function is provided', function() {
      var tickGenerator = function() {
        var values = []
        for (var i = 0; i <= 300; i += 50) {
          values.push(i)
        }
        return values
      }
      beforeEach(function() {
        args.axis.x = {
          tick: {
            values: tickGenerator
          }
        }
        chart = c3.generate(args)
        ;(window as any).generatedTicks = tickGenerator() // This should be removed from window
      })

      it('should use function to generate ticks', function() {
        d3.select('.c3-axis-x')
          .selectAll('g.tick')
          .each(function(d, i) {
            var tick = d3
              .select(this)
              .select('text')
              .text()
            expect(+tick).toBe((window as any).generatedTicks[i])
          })
      })
    })
  })

  describe('axis.x.tick.width', function() {
    describe('indexed x axis and y/y2 axis', function() {
      describe('not rotated', function() {
        beforeAll(function() {
          args = {
            data: {
              columns: [
                ['data1', 30, 200, 100, 400, 150, 250],
                ['data2', 50, 20, 10, 40, 15, 25]
              ],
              axes: {
                data2: 'y2'
              }
            },
            axis: {
              y2: {
                show: true
              }
            }
          }
        })

        it('should construct indexed x axis properly', function() {
          var ticks = chart.internal.main
              .select('.c3-axis-x')
              .selectAll('g.tick'),
            expectedX = '0',
            expectedDy = '.71em'
          expect(ticks.size()).toBe(6)
          ticks.each(function(d, i) {
            var tspans = d3.select(this).selectAll('tspan')
            expect(tspans.size()).toBe(1)
            tspans.each(function() {
              var tspan = d3.select(this)
              expect(tspan.text()).toBe(i + '')
              expect(tspan.attr('x')).toBe(expectedX)
              expect(tspan.attr('dy')).toBe(expectedDy)
            })
          })
        })

        describe('should set axis.x.tick.format', function() {
          beforeAll(function() {
            args.axis.x = {
              tick: {
                format: function() {
                  return 'very long tick text on x axis'
                }
              }
            }
          })

          it('should split x axis tick text to multiple lines', function() {
            var ticks = chart.internal.main
                .select('.c3-axis-x')
                .selectAll('g.tick'),
              expectedTexts = ['very long tick text', 'on x axis'],
              expectedX = '0'
            expect(ticks.size()).toBe(6)
            ticks.each(function() {
              var tspans = d3.select(this).selectAll('tspan')
              expect(tspans.size()).toBe(2)
              tspans.each(function(d, i) {
                var tspan = d3.select(this)
                expect(tspan.text()).toBe(expectedTexts[i])
                expect(tspan.attr('x')).toBe(expectedX)
                if (i === 0) {
                  expect(tspan.attr('dy')).toBe('.71em')
                } else {
                  expect(tspan.attr('dy')).toBeGreaterThan(8)
                }
              })
            })
          })

          it('should construct y axis properly', function() {
            var ticks = chart.internal.main
                .select('.c3-axis-y')
                .selectAll('g.tick'),
              expectedX = '-9',
              expectedDy = '3'
            expect(ticks.size()).toBe(9)
            ticks.each(function(d) {
              var tspans = d3.select(this).selectAll('tspan')
              expect(tspans.size()).toBe(1)
              tspans.each(function() {
                var tspan = d3.select(this)
                expect(tspan.text()).toBe(d + '')
                expect(tspan.attr('x')).toBe(expectedX)
                expect(tspan.attr('dy')).toBe(expectedDy)
              })
            })
          })

          it('should construct y2 axis properly', function() {
            var ticks = chart.internal.main
                .select('.c3-axis-y2')
                .selectAll('g.tick'),
              expectedX = '9',
              expectedDy = '3'
            expect(ticks.size()).toBe(9)
            ticks.each(function(d) {
              var tspans = d3.select(this).selectAll('tspan')
              expect(tspans.size()).toBe(1)
              tspans.each(function() {
                var tspan = d3.select(this)
                expect(tspan.text()).toBe(d + '')
                expect(tspan.attr('x')).toBe(expectedX)
                expect(tspan.attr('dy')).toBe(expectedDy)
              })
            })
          })
        })

        describe('should set big values in y', function() {
          beforeAll(function() {
            args.data.columns = [
              ['data1', 3000000000000000, 200, 100, 400, 150, 250],
              ['data2', 50, 20, 10, 40, 15, 25]
            ]
          })

          it('should not split y axis tick text to multiple lines', function() {
            var ticks = chart.internal.main
              .select('.c3-axis-y2')
              .selectAll('g.tick')
            ticks.each(function() {
              var tspans = d3.select(this).selectAll('tspan')
              expect(tspans.size()).toBe(1)
            })
          })
        })
      })

      describe('rotated', function() {
        beforeAll(function() {
          args.axis.rotated = true
        })

        it('should split x axis tick text to multiple lines', function() {
          var ticks = chart.internal.main
              .select('.c3-axis-x')
              .selectAll('g.tick'),
            expectedTexts = ['very long tick text on', 'x axis'],
            expectedX = '-9'
          expect(ticks.size()).toBe(6)
          ticks.each(function() {
            var tspans = d3.select(this).selectAll('tspan')
            expect(tspans.size()).toBe(2)
            tspans.each(function(d, i) {
              var tspan = d3.select(this)
              expect(tspan.text()).toBe(expectedTexts[i])
              expect(tspan.attr('x')).toBe(expectedX)
              if (i === 0) {
                expect(tspan.attr('dy')).toBeLessThan(0)
              } else {
                expect(tspan.attr('dy')).toBeGreaterThan(9)
              }
            })
          })
        })

        it('should not split y axis tick text to multiple lines', function() {
          var ticks = chart.internal.main
              .select('.c3-axis-y')
              .selectAll('g.tick'),
            expectedTexts = [
              '0',
              '500000000000000',
              '1000000000000000',
              '1500000000000000',
              '2000000000000000',
              '2500000000000000',
              '3000000000000000'
            ],
            expectedX = '0',
            expectedDy = '.71em'
          expect(ticks.size()).toBe(7)
          ticks.each(function(d, i) {
            var tspans = d3.select(this).selectAll('tspan')
            expect(tspans.size()).toBe(1)
            tspans.each(function() {
              var tspan = d3.select(this)
              expect(tspan.text()).toBe(expectedTexts[i])
              expect(tspan.attr('x')).toBe(expectedX)
              expect(tspan.attr('dy')).toBe(expectedDy)
            })
          })
        })
      })
    })

    describe('category axis', function() {
      describe('not rotated', function() {
        beforeAll(function() {
          args = {
            data: {
              x: 'x',
              columns: [
                [
                  'x',
                  'this is a very long tick text on category axis',
                  'cat1',
                  'cat2',
                  'cat3',
                  'cat4',
                  'cat5'
                ],
                ['data1', 30, 200, 100, 400, 150, 250],
                ['data2', 50, 20, 10, 40, 15, 25]
              ]
            },
            axis: {
              x: {
                type: 'category'
              }
            }
          }
        })

        it('should locate ticks properly', function() {
          var ticks = chart.internal.main
            .select('.c3-axis-x')
            .selectAll('g.tick')
          ticks.each(function(d, i) {
            var tspans = d3.select(this).selectAll('tspan'),
              expectedX = '0',
              expectedDy = '.71em'
            if (i > 0) {
              // i === 0 should be checked in next test
              expect(tspans.size()).toBe(1)
              tspans.each(function() {
                var tspan = d3.select(this)
                expect(tspan.attr('x')).toBe(expectedX)
                expect(tspan.attr('dy')).toBe(expectedDy)
              })
            }
          })
        })

        xit('should split tick text properly', function() {
          var tick = chart.internal.main.select('.c3-axis-x').select('g.tick'),
            tspans = tick.selectAll('tspan'),
            expectedTickTexts = [
              'this is a very long',
              'tick text on category',
              'axis'
            ],
            expectedX = '0'
          expect(tspans.size()).toBe(3)
          tspans.each(function(d, i) {
            var tspan = d3.select(this)
            expect(tspan.text()).toBe(expectedTickTexts[i])
            expect(tspan.attr('x')).toBe(expectedX)
            // unable to define pricise number because it differs depends on environment..
            if (i === 0) {
              expect(tspan.attr('dy')).toBe('.71em')
            } else {
              expect(tspan.attr('dy')).toBeGreaterThan(8)
            }
          })
        })
      })

      describe('rotated', function() {
        beforeAll(function() {
          args.axis.rotated = true
        })

        it('should locate ticks on rotated axis properly', function() {
          var ticks = chart.internal.main
            .select('.c3-axis-x')
            .selectAll('g.tick')
          ticks.each(function(d, i) {
            var tspans = d3.select(this).selectAll('tspan'),
              expectedX = '-9',
              expectedDy = '3'
            if (i > 0) {
              // i === 0 should be checked in next test
              expect(tspans.size()).toBe(1)
              tspans.each(function() {
                var tspan = d3.select(this)
                expect(tspan.attr('x')).toBe(expectedX)
                expect(tspan.attr('dy')).toBe(expectedDy)
              })
            }
          })
        })

        it('should split tick text on rotated axis properly', function() {
          var tick = chart.internal.main.select('.c3-axis-x').select('g.tick'),
            tspans = tick.selectAll('tspan'),
            expectedTickTexts = [
              'this is a very long',
              'tick text on category',
              'axis'
            ],
            expectedX = '-9'
          expect(tspans.size()).toBe(3)
          tspans.each(function(d, i) {
            var tspan = d3.select(this)
            expect(tspan.text()).toBe(expectedTickTexts[i])
            expect(tspan.attr('x')).toBe(expectedX)
            // unable to define pricise number because it differs depends on environment..
            if (i === 0) {
              expect(tspan.attr('dy')).toBeLessThan(0)
            } else {
              expect(tspan.attr('dy')).toBeGreaterThan(8)
            }
          })
        })
      })

      describe('option used', function() {
        describe('as null', function() {
          beforeAll(function() {
            //'without split ticks',
            args.axis.x.tick = {
              multiline: false
            }
          })

          it('should split x tick', function() {
            var tick = chart.internal.main
                .select('.c3-axis-x')
                .select('g.tick'),
              tspans = tick.selectAll('tspan')
            expect(tspans.size()).toBe(1)
          })
        })

        describe('as value', function() {
          beforeAll(function() {
            // 'without split ticks',
            args.axis.x.tick = {
              width: 150
            }
          })

          it('should split x tick to 2 lines properly', function() {
            var tick = chart.internal.main
                .select('.c3-axis-x')
                .select('g.tick'),
              tspans = tick.selectAll('tspan'),
              expectedTickTexts = [
                'this is a very long tick text on',
                'category axis'
              ],
              expectedX = '-9'
            expect(tspans.size()).toBe(2)
            tspans.each(function(d, i) {
              var tspan = d3.select(this)
              expect(tspan.text()).toBe(expectedTickTexts[i])
              expect(tspan.attr('x')).toBe(expectedX)
              // unable to define pricise number because it differs depends on environment..
              if (i === 0) {
                expect(tspan.attr('dy')).toBeLessThan(0)
              } else {
                expect(tspan.attr('dy')).toBeGreaterThan(8)
              }
            })
          })
        })

        describe('with multilineMax', function() {
          beforeAll(function() {
            args.axis.x.tick = {
              multiline: true,
              multilineMax: 2
            }
          })

          it('should ellipsify x tick properly', function() {
            var tick = chart.internal.main.select('.c3-axis-x').select('g.tick')
            var tspans = tick.selectAll('tspan')
            var expectedTickText = [
              'this is a very long',
              'tick text on categ...'
            ]

            expect(tspans.size()).toBe(2)

            tspans.each(function(d, i) {
              var tspan = d3.select(this)
              expect(tspan.text()).toBe(expectedTickText[i])
            })
          })
        })
      })
    })

    describe('with axis.x.tick.format', function() {
      beforeAll(function() {
        // 'with axis.x.tick.format',
        args.axis.x.tick.format = function() {
          return ['this is a very long tick text', 'on category axis']
        }
      })

      it('should have multiline tick text', function() {
        var tick = chart.internal.main.select('.c3-axis-x').select('g.tick'),
          tspans = tick.selectAll('tspan'),
          expectedTickTexts = [
            'this is a very long tick text',
            'on category axis'
          ]
        expect(tspans.size()).toBe(2)
        tspans.each(function(d, i) {
          var tspan = d3.select(this)
          expect(tspan.text()).toBe(expectedTickTexts[i])
        })
      })
    })
  })

  describe('axis.x.tick.rotate', function() {
    describe('not rotated', function() {
      beforeAll(function() {
        args = {
          data: {
            x: 'x',
            columns: [
              [
                'x',
                'category 1',
                'category 2',
                'category 3',
                'category 4',
                'category 5',
                'category 6'
              ],
              ['data1', 30, 200, 100, 400, 150, 250],
              ['data2', 50, 20, 10, 40, 15, 25]
            ]
          },
          axis: {
            x: {
              type: 'category',
              tick: {
                rotate: 60
              }
            }
          }
        }
      })

      it('should rotate tick texts', function() {
        chart.internal.main.selectAll('.c3-axis-x g.tick').each(function() {
          var tick = d3.select(this),
            text = tick.select('text'),
            tspan = text.select('tspan')
          expect(text.attr('transform')).toBe('rotate(60)')
          expect(text.attr('y')).toBe('1.5')
          expect(tspan.attr('dx')).toBe('6.928203230275509')
        })
      })

      it('should have automatically calculated x axis height', function() {
        var box = chart.internal.main
            .select('.c3-axis-x')
            .node()
            .getBoundingClientRect(),
          height = chart.internal.getHorizontalAxisHeight('x')
        expect(box.height).toBeGreaterThan(50)
        expect(height).toBeCloseTo(76, -1.3) // @TODO make this test better
      })
    })
  })

  describe('axis.y.tick.rotate', function() {
    describe('not rotated', function() {
      beforeAll(function() {
        args = {
          data: {
            columns: [
              ['data1', 30, 200, 100, 400, 150, 250, 100, 600],
              ['data2', 50, 20, 10, 40, 15, 25]
            ]
          },
          axis: {
            rotated: true,
            y: {
              tick: {
                rotate: 45
              }
            }
          }
        }
      })

      it('should rotate tick texts', function() {
        chart.internal.main.selectAll('.c3-axis-y g.tick').each(function() {
          var tick = d3.select(this),
            text = tick.select('text'),
            tspan = text.select('tspan')
          expect(text.attr('transform')).toBe('rotate(45)')
          expect(text.attr('y')).toBe('4')
          expect(tspan.attr('dx')).toBeCloseTo(5.6, 0)
        })
      })

      it('should have automatically calculated y axis width', function() {
        var box = chart.internal.main
          .select('.c3-axis-y')
          .node()
          .getBoundingClientRect()
        expect(box.width).toBeCloseTo(590, 1)
      })
    })
  })

  describe('axis.x.tick.fit', function() {
    describe('axis.x.tick.fit = true', function() {
      beforeAll(function() {
        // 'should set args for indexed data',
        args = {
          data: {
            columns: [
              ['data1', 30, 200, 100, 400, 150, 250],
              ['data2', 50, 20, 10, 40, 15, 25],
              ['data3', 150, 120, 110, 140, 115, 125]
            ]
          }
        }
      })

      it('should show fitted ticks on indexed data', function() {
        var ticks = chart.internal.main.selectAll('.c3-axis-x g.tick')
        expect(ticks.size()).toBe(6)
      })

      describe('should set args for x-based data', function() {
        beforeAll(function() {
          args = {
            data: {
              x: 'x',
              columns: [
                ['x', 10, 20, 100, 110, 200, 1000],
                ['data1', 30, 200, 100, 400, 150, 250],
                ['data2', 50, 20, 10, 40, 15, 25],
                ['data3', 150, 120, 110, 140, 115, 125]
              ]
            }
          }
        })

        it('should show fitted ticks on indexed data', function() {
          var ticks = chart.internal.main.selectAll('.c3-axis-x g.tick')
          expect(ticks.size()).toBe(6)
        })

        it('should show fitted ticks after hide and show', function() {
          chart.hide()
          chart.show()
          var ticks = chart.internal.main.selectAll('.c3-axis-x g.tick')
          expect(ticks.size()).toBe(6)
        })
      })
    })

    describe('axis.x.tick.fit = false', function() {
      describe('should set args for indexed data', function() {
        beforeAll(function() {
          args = {
            data: {
              columns: [
                ['data1', 30, 200, 100, 400, 150, 250],
                ['data2', 50, 20, 10, 40, 15, 25],
                ['data3', 150, 120, 110, 140, 115, 125]
              ]
            },
            axis: {
              x: {
                tick: {
                  fit: false
                }
              }
            }
          }
        })

        it('should show fitted ticks on indexed data', function() {
          var ticks = chart.internal.main.selectAll('.c3-axis-x g.tick')
          expect(ticks.size()).toBe(11)
        })
      })

      describe('should set args for x-based data', function() {
        beforeAll(function() {
          args.data = {
            x: 'x',
            columns: [
              ['x', 10, 20, 100, 110, 200, 1000],
              ['data1', 30, 200, 100, 400, 150, 250],
              ['data2', 50, 20, 10, 40, 15, 25],
              ['data3', 150, 120, 110, 140, 115, 125]
            ]
          }
        })

        it('should show fitted ticks on indexed data', function() {
          var ticks = chart.internal.main.selectAll('.c3-axis-x g.tick')
          expect(ticks.size()).toBe(10)
        })

        it('should show fitted ticks after hide and show', function() {
          chart.hide()
          chart.show()
          var ticks = chart.internal.main.selectAll('.c3-axis-x g.tick')
          expect(ticks.size()).toBe(10)
        })
      })
    })
  })

  describe('axis.y.inner', function() {
    beforeAll(function() {
      args = {
        data: {
          columns: [
            ['data1', 30, 200, 100, 400, 150, 250],
            ['data2', 50, 20, 10, 40, 15, 25]
          ]
        },
        axis: {
          y: {
            inner: false
          }
        }
      }
    })

    it('should not have inner y axis', function() {
      var paddingLeft = chart.internal.getCurrentPaddingLeft(),
        tickTexts = chart.internal.main.selectAll('.c3-axis-y g.tick text')
      expect(paddingLeft).toBeGreaterThan(19)
      tickTexts.each(function() {
        expect(+d3.select(this).attr('x')).toBeLessThan(0)
      })
    })

    describe('with inner y axis', function() {
      beforeAll(function() {
        args.axis.y.inner = true
      })

      it('should have inner y axis', function() {
        var paddingLeft = chart.internal.getCurrentPaddingLeft(),
          tickTexts = chart.internal.main.selectAll('.c3-axis-y g.tick text')
        expect(paddingLeft).toBe(1)
        tickTexts.each(function() {
          expect(+d3.select(this).attr('x')).toBeGreaterThan(0)
        })
      })
    })
  })

  describe('axis.y2.inner', function() {
    beforeAll(function() {
      args = {
        data: {
          columns: [
            ['data1', 30, 200, 100, 400, 150, 250],
            ['data2', 50, 20, 10, 40, 15, 25]
          ]
        },
        axis: {
          y2: {
            show: true,
            inner: false
          }
        }
      }
    })

    it('should not have inner y axis', function() {
      var paddingRight = chart.internal.getCurrentPaddingRight(),
        tickTexts = chart.internal.main.selectAll('.c3-axis-2y g.tick text')
      expect(paddingRight).toBeGreaterThan(19)
      tickTexts.each(function() {
        expect(+d3.select(this).attr('x')).toBeGreaterThan(0)
      })
    })

    describe('with inner y axis', function() {
      beforeAll(function() {
        args.axis.y2.inner = true
      })

      it('should have inner y axis', function() {
        var paddingRight = chart.internal.getCurrentPaddingRight(),
          tickTexts = chart.internal.main.selectAll('.c3-axis-2y g.tick text')
        expect(paddingRight).toBe(2)
        tickTexts.each(function() {
          expect(+d3.select(this).attr('x')).toBeLessThan(0)
        })
      })
    })
  })

  describe('axis.x.label', function() {
    beforeAll(function() {
      args = {
        data: {
          columns: [
            ['somewhat long 1', 30, 200, 100, 400, 150, 250],
            ['somewhat long 2', 50, 20, 10, 40, 15, 25]
          ]
        },
        axis: {
          x: {
            show: true,
            label: {
              text: 'Label of X axis'
            }
          }
        }
      }
    })

    it('renders label text properly', () => {
      expect(d3.select('.c3-axis-x-label').text()).toEqual('Label of X axis')
    })

    describe('outer label position', function() {
      beforeAll(function() {
        args.axis.x.label.position = 'outer-center'
      })

      it('renders position properly', () => {
        const label = d3.select('.c3-axis-x-label')

        expect(label.attr('dy')).toEqual('30')
      })

      describe('with rotated tick', function() {
        beforeAll(function() {
          args.axis.x.tick = {
            rotate: 90
          }
        })

        it('renders position properly', () => {
          const label = d3.select('.c3-axis-x-label')

          expect(label.attr('dy')).toBeGreaterThan(30)
        })
      })
    })

    describe('inner label position', function() {
      beforeAll(function() {
        args.axis.x.label.position = 'inner-center'
      })

      it('renders position properly', () => {
        const label = d3.select('.c3-axis-x-label')

        expect(label.attr('dy')).toEqual('-0.5em')
      })

      describe('with rotated tick', function() {
        beforeAll(function() {
          args.axis.x.tick = {
            rotate: 90
          }
        })

        it('renders position properly', () => {
          const label = d3.select('.c3-axis-x-label')

          expect(label.attr('dy')).toEqual('-0.5em')
        })
      })
    })
  })
})
