From b5c9a6d54ee74f21b9c6c28669f211da0c66cff8 Mon Sep 17 00:00:00 2001 From: Kris Salvador Date: Tue, 12 Jun 2018 15:32:41 -0400 Subject: [PATCH] Add more tests (#83) * Add YTicks spec * XGrid spec * Add XGrid spec static test * YGrid spec * XYPlot spec * Separate test dom and lint * Lint browser tests * AreaChart spec * LineChart spec --- package.json | 10 +- src/AreaChart.js | 8 +- src/YGrid.js | 2 +- tests/browser/index.js | 13 +- tests/browser/spec/XAxis.spec.js | 44 +++--- tests/browser/webpack.config.test.js | 52 +++---- tests/eslint.spec.js | 2 +- tests/jsdom/spec/AreaBarChart.spec.js | 2 +- tests/jsdom/spec/AreaChart.spec.js | 131 ++++++++++++++++ tests/jsdom/spec/LineChart.spec.js | 24 +++ tests/jsdom/spec/XGrid.spec.js | 75 ++++++++++ tests/jsdom/spec/XYPlot.spec.js | 47 +++++- tests/jsdom/spec/YGrid.spec.js | 75 ++++++++++ tests/jsdom/spec/YTicks.spec.js | 208 ++++++++++++++++++++++++++ tests/jsdom/utils.js | 31 ++-- 15 files changed, 641 insertions(+), 83 deletions(-) create mode 100644 tests/jsdom/spec/AreaChart.spec.js create mode 100644 tests/jsdom/spec/XGrid.spec.js create mode 100644 tests/jsdom/spec/YGrid.spec.js create mode 100644 tests/jsdom/spec/YTicks.spec.js diff --git a/package.json b/package.json index 299c6b9a..43b91d28 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ }, "scripts": { "lint": "eslint ./src", - "lint-fix": "eslint ./src ./tests/jsdom/spec --ext .js --fix", + "lint-fix": "eslint ./src ./tests --ext .js --fix", "prepublish": "npm run build", "build": "npm run build-lib && npm run build-css && npm run docs", "dev": "webpack-dev-server --config webpack.config.base.js", @@ -23,13 +23,15 @@ "make-docs": "node scripts/makeDocs.js", "clean": "node scripts/clean.js", "serve": "python -m SimpleHTTPServer", - "test": "npm run test-jsdom-and-lint", + "test": "npm run test-jsdom && npm run test-lint", "test-files": "env NODE_PATH=$NODE_PATH:$PWD/src BABEL_ENV=production mocha --compilers js:babel-register --require tests/jsdom/setup.js --recursive", "test-browser": "webpack-dev-server --config tests/browser/webpack.config.test.js", - "test-jsdom-and-lint": - "env NODE_PATH=$NODE_PATH:$PWD/src BABEL_ENV=production mocha --compilers js:babel-register --require tests/jsdom/setup.js --recursive tests/jsdom/spec tests/eslint.spec.js", + "test-jsdom": + "env NODE_PATH=$NODE_PATH:$PWD/src BABEL_ENV=production mocha --compilers js:babel-register --require tests/jsdom/setup.js --recursive tests/jsdom/spec", + "test-lint": + "env NODE_PATH=$NODE_PATH:$PWD/src BABEL_ENV=production mocha --compilers js:babel-register --require tests/jsdom/setup.js --recursive tests/eslint.spec.js", "test-watch": "env NODE_PATH=$NODE_PATH:$PWD/src BABEL_ENV=production mocha --watch --compilers js:babel-register --require tests/jsdom/setup.js --recursive tests/jsdom/spec" }, diff --git a/src/AreaChart.js b/src/AreaChart.js index 173d92a0..ab071c45 100644 --- a/src/AreaChart.js +++ b/src/AreaChart.js @@ -172,7 +172,7 @@ export default class AreaChart extends React.Component { const pathStyleBelow = pathStyleNegative || pathStyle || {}; return ( - + @@ -180,13 +180,13 @@ export default class AreaChart extends React.Component { + + {ticks.map((tick, i) => { return ( { +describe("XAxis", () => { const width = 500; const height = 300; - it('extends the scale domain if to include custom `ticks` if passed', () => { + it("extends the scale domain if to include custom `ticks` if passed", () => { const props = { - width, height, - scaleType: {x: 'linear', y: 'linear'}, - margin: {top: 11, bottom: 22, left: 33, right: 44} + width, + height, + scaleType: { x: "linear", y: "linear" }, + margin: { top: 11, bottom: 22, left: 33, right: 44 } }; - const tree = - - - ; + const tree = ( + + + + + ); const rendered = mount(tree).find(XAxis); expect(rendered.props().domain.x).to.deep.equal([-5, 10]); expect(rendered.props().domain.y).to.deep.equal([0, 10]); }); - it('rounds domain to nice numbers if `nice` option is true', () => { + it("rounds domain to nice numbers if `nice` option is true", () => { const props = { - width, height, - scaleType: {x: 'linear', y: 'linear'}, - margin: {top: 11, bottom: 22, left: 33, right: 44} + width, + height, + scaleType: { x: "linear", y: "linear" }, + margin: { top: 11, bottom: 22, left: 33, right: 44 } }; const niceXChart = mount( @@ -46,5 +50,5 @@ describe('XAxis', () => { expect(niceXChart.props().domain.x).to.deep.equal([0, 10]); expect(niceXChart.props().domain.y).to.deep.equal([0.8, 9.7]); - }) + }); }); diff --git a/tests/browser/webpack.config.test.js b/tests/browser/webpack.config.test.js index 89c2c5fc..4d81342e 100644 --- a/tests/browser/webpack.config.test.js +++ b/tests/browser/webpack.config.test.js @@ -1,30 +1,28 @@ -var path = require('path'); -var webpack = require('webpack'); -var _ = require('lodash'); -var HtmlPlugin = require('html-webpack-plugin'); -var CleanPlugin = require('clean-webpack-plugin'); +var path = require("path"); +var webpack = require("webpack"); +var _ = require("lodash"); +var HtmlPlugin = require("html-webpack-plugin"); +var CleanPlugin = require("clean-webpack-plugin"); -console.log('dirname', __dirname); +console.log("dirname", __dirname); module.exports = { context: __dirname, - entry: [ - path.join(__dirname, 'index.js') - ], + entry: [path.join(__dirname, "index.js")], output: { - path: path.join(__dirname, 'build'), - filename: 'bundle.[hash].js', + path: path.join(__dirname, "build"), + filename: "bundle.[hash].js" }, - devtool: 'source-map', + devtool: "source-map", plugins: [ new webpack.NoEmitOnErrorsPlugin(), new HtmlPlugin({ title: "Reactochart Tests", - template: path.join(__dirname, 'index_html.ejs'), + template: path.join(__dirname, "index_html.ejs") }), - new CleanPlugin([path.join(__dirname, 'build')]) + new CleanPlugin([path.join(__dirname, "build")]) ], resolve: { - extensions: ['.js', '.jsx'], + extensions: [".js", ".jsx"], modules: ["node_modules", path.resolve(__dirname, "../..")] }, module: { @@ -32,30 +30,28 @@ module.exports = { { test: /\.jsx?$/, exclude: /node_modules/, - use: [{loader: 'babel-loader'}] + use: [{ loader: "babel-loader" }] }, { test: /\.less?$/, use: [ - {loader: 'style-loader'}, - {loader: 'css-loader'}, - {loader: 'less-loader'} + { loader: "style-loader" }, + { loader: "css-loader" }, + { loader: "less-loader" } ] }, { test: /\.json$/, - use: [{loader: 'json-loader'}] + use: [{ loader: "json-loader" }] } ] }, // https://github.com/airbnb/enzyme/issues/503 externals: { - 'jsdom': 'window', - 'cheerio': 'window', - 'react/lib/ExecutionEnvironment': true, - 'react/addons': true, - 'react/lib/ReactContext': 'window' - }, + jsdom: "window", + cheerio: "window", + "react/lib/ExecutionEnvironment": true, + "react/addons": true, + "react/lib/ReactContext": "window" + } }; - - diff --git a/tests/eslint.spec.js b/tests/eslint.spec.js index ab6f4c96..b095483e 100644 --- a/tests/eslint.spec.js +++ b/tests/eslint.spec.js @@ -6,7 +6,7 @@ import { CLIEngine } from "eslint"; import { expect, assert } from "chai"; const srcPaths = glob.sync("./src/*.js"); -const testPaths = glob.sync("./tests/jsdom/spec/*.js"); +const testPaths = glob.sync("./tests/*.js"); const engine = new CLIEngine({ envs: ["node", "mocha"], useEslintrc: true diff --git a/tests/jsdom/spec/AreaBarChart.spec.js b/tests/jsdom/spec/AreaBarChart.spec.js index a1144bda..f30b06b4 100644 --- a/tests/jsdom/spec/AreaBarChart.spec.js +++ b/tests/jsdom/spec/AreaBarChart.spec.js @@ -3,7 +3,7 @@ import * as d3 from "d3"; import { expect } from "chai"; import { mount } from "enzyme"; -import { XYPlot, AreaBarChart, RangeRect } from "../../../src/index.js"; +import { AreaBarChart, RangeRect } from "../../../src/index.js"; import { getValue } from "../../../src/utils/Data.js"; describe("AreaBarChart", () => { diff --git a/tests/jsdom/spec/AreaChart.spec.js b/tests/jsdom/spec/AreaChart.spec.js new file mode 100644 index 00000000..1df3fa98 --- /dev/null +++ b/tests/jsdom/spec/AreaChart.spec.js @@ -0,0 +1,131 @@ +import React from "react"; +import * as d3 from "d3"; +import { expect } from "chai"; +import { mount } from "enzyme"; +import _ from "lodash"; +import { AreaChart } from "../../../src/index.js"; + +import { combineDatasets } from "../../../src/utils/Data.js"; + +function randomWalk(length = 100, start = 0, variance = 10) { + return _.reduce( + _.range(length - 1), + (sequence, i) => { + return sequence.concat(_.last(sequence) + _.random(-variance, variance)); + }, + [start] + ); +} + +function randomWalkTimeSeries( + length = 100, + start = 0, + variance = 10, + startDate = new Date(2015, 0, 1) +) { + let date = startDate; + return randomWalk(length, start, variance).map((n, i) => { + date = new Date(date.getTime() + 24 * 60 * 60 * 1000); + return [date, n]; + }); +} + +describe("AreaChart", () => { + const areaChartProps = { + data: _.range(41), + x: d => d, + y: d => Math.sin(d / 10) * 10, + yEnd: d => Math.cos((d + 1) / 10) * 10, + pathClassName: "my-path", + xScale: d3.scaleLinear().domain([0, 41]), + yScale: d3.scaleLinear().domain([0, 10]), + pathStyle: { fill: "red" } + }; + + const data1 = randomWalkTimeSeries(115).map(([x, y]) => ({ x, y })); + const data2 = randomWalkTimeSeries(115).map(([x, y]) => ({ x, y })); + + // we have two datasets, but AreaChart takes one combined dataset + // so combine the two datasets into one using the combineDatasets utility function + // (from 'reactochart/utils/Data') + const combined = combineDatasets( + [ + { data: data1, combineKey: "x", dataKeys: { y: "y0" } }, + { data: data2, combineKey: "x", dataKeys: { y: "y1" } } + ], + "x" + ); + + const differenceAreaChartProps = { + data: combined, + isDifference: true, + pathStylePositive: { fill: "blue" }, + pathStyleNegative: { fill: "green" }, + x: d => d.x, + y: d => d.y0, + yEnd: d => d.y1 + }; + + it("passes props correctly to path", () => { + let chart = mount(); + let path = chart.find("path"); + + expect(path.props().className).to.contain("my-path"); + expect(path.props().style).to.equal(areaChartProps.pathStyle); + + chart = mount( + + ); + path = chart.find("path"); + + path.forEach((p, index) => { + if (index < 2) { + expect(p.props().className).to.not.contain( + areaChartProps.pathClassName + ); + } else if (index == 3) { + expect(p.props().style.fill).to.equal( + differenceAreaChartProps.pathStyleNegative.fill + ); + expect(p.props().className).to.contain(areaChartProps.pathClassName); + } else { + expect(p.props().style.fill).to.equal( + differenceAreaChartProps.pathStylePositive.fill + ); + expect(p.props().className).to.contain(areaChartProps.pathClassName); + } + }); + }); + + it("renders the expected group and the expected number of paths", () => { + let chart = mount(); + let path = chart.find("path"); + let group = chart.find("g"); + + expect(group.length).to.equal(1); + expect(group.props().className).to.equal("rct-area-chart"); + expect(path.length).to.equal(1); + + chart = mount( + + ); + path = chart.find("path"); + group = chart.find("g"); + + expect(group.length).to.equal(1); + expect(group.props().className).to.equal("rct-area-chart--difference"); + expect(path.length).to.equal(4); + }); + + it("getDomain returns correctly", () => { + const domainProps = { + data: _.range(10), + x: () => x, + y: () => 0, + yEnd: d => d + 2 + }; + const domain = { yDomain: [0, 11] }; + + expect(AreaChart.getDomain(domainProps)).to.eql(domain); + }); +}); diff --git a/tests/jsdom/spec/LineChart.spec.js b/tests/jsdom/spec/LineChart.spec.js index a1c50662..409d0b30 100644 --- a/tests/jsdom/spec/LineChart.spec.js +++ b/tests/jsdom/spec/LineChart.spec.js @@ -18,6 +18,30 @@ describe("LineChart", () => { .domain([0, 1]) .range([100, 0]); + it("passes props correctly to group and path elements", () => { + const props = { + xScale: d3 + .scaleLinear() + .domain([0, 2]) + .range([0, 100]), + yScale: d3 + .scaleLinear() + .domain([0, 1]) + .range([100, 0]), + data: [[0, 0.5], [1, 1], [2, 0.25]], + x: d => d[0], + y: d => d[1], + lineClassName: "my-line", + lineStyle: { fill: "blue" } + }; + const chart = mount(); + const group = chart.find("g"); + const path = chart.find("path"); + + expect(path.props().style).to.equal(props.lineStyle); + expect(group.props().className).to.contain(props.lineClassName); + }); + it("renders a line with number X & Y scales", () => { // make simple number-number line chart with 3 datapoints const props = { diff --git a/tests/jsdom/spec/XGrid.spec.js b/tests/jsdom/spec/XGrid.spec.js new file mode 100644 index 00000000..3698c22e --- /dev/null +++ b/tests/jsdom/spec/XGrid.spec.js @@ -0,0 +1,75 @@ +import React from "react"; +import * as d3 from "d3"; +import _ from "lodash"; +import { expect } from "chai"; +import { mount } from "enzyme"; + +import { XGrid, XLine } from "../../../src/index.js"; +import { getScaleTicks, getTickDomain } from "../../../src/utils/Scale"; + +describe("XGrid", () => { + const props = { + height: 10, + spacingTop: 10, + spacingBottom: 10, + spacingLeft: 10, + spacingRight: 10, + lineClassName: "xgrid-line-class", + lineStyle: { stroke: "blue" }, + xScale: d3.scaleLinear().domain([0, 100]) + }; + + it("passes props correctly to XLine", () => { + const xGrid = mount(); + const xLines = xGrid.find(XLine); + + xLines.getNodes().forEach(xLine => { + const xLineProps = xLine.props; + + expect(xLineProps.className).to.contain(props.lineClassName); + expect(xLineProps.style).to.equal(props.lineStyle); + expect(xLineProps.spacingTop).to.equal(props.spacingTop); + expect(xLineProps.spacingBottom).to.equal(props.spacingBottom); + expect(xLineProps.spacingLeft).to.equal(props.spacingLeft); + expect(xLineProps.spacingRight).to.equal(props.spacingRight); + expect(xLineProps.xScale).to.equal(props.xScale); + expect(xLineProps.height).to.equal(props.height); + }); + }); + + it("renders the correct amount of XLines given tickCount", () => { + const tickCount = 50; + const xGrid = mount(); + const group = xGrid.find("g"); + + expect(group).to.have.lengthOf(1); + expect(group.getDOMNode().className).to.equal("rct-chart-grid-x"); + + const xLines = xGrid.find(XLine); + const numTicksMade = getScaleTicks(props.xScale, null, tickCount); + + expect(xLines).to.have.lengthOf(numTicksMade.length); + }); + + it("renders the correct amount of XLines given ticks", () => { + const ticks = [0, 25, 50, 100]; + const xGrid = mount(); + const group = xGrid.find("g"); + + expect(group).to.have.lengthOf(1); + expect(group.getDOMNode().className).to.equal("rct-chart-grid-x"); + + const xLines = xGrid.find(XLine); + expect(xLines).to.have.lengthOf(ticks.length); + }); + + it("getTickDomain works as expected", () => { + const ticks = [0, 25, 50, 100]; + + const result = getTickDomain(props.xScale, { ...props, ticks }); + + expect(XGrid.getTickDomain({ ...props, ticks })).to.eql({ + xTickDomain: result + }); + }); +}); diff --git a/tests/jsdom/spec/XYPlot.spec.js b/tests/jsdom/spec/XYPlot.spec.js index 702f0ad1..682e690c 100644 --- a/tests/jsdom/spec/XYPlot.spec.js +++ b/tests/jsdom/spec/XYPlot.spec.js @@ -1,17 +1,33 @@ import React from "react"; import ReactDOM from "react-dom"; import * as d3 from "d3"; +import sinon from "sinon"; import { expect } from "chai"; -import { mount, shallow } from "enzyme"; +import { mount } from "enzyme"; -import { XYPlot, LineChart } from "../../../src/index.js"; - -const commonXYProps = { xDomain: [0, 10], yDomain: [0, 100] }; +import { XYPlot } from "../../../src/index.js"; describe("XYPlot", () => { - it("renders SVG with given width & height (or a default)", () => { + const commonXYProps = { + xDomain: [0, 10], + yDomain: [0, 100], + xyPlotClassName: "xy-plot", + onMouseMove: sinon.spy(), + onMouseEnter: sinon.spy(), + onMouseLeave: sinon.spy(), + onMouseDown: sinon.spy(), + onMouseUp: sinon.spy() + }; + + it("renders SVG with given width, height and className (or a default)", () => { const chart = mount(); - const node = chart.find("svg").getNode(); + const svg = chart.find("svg"); + + expect(svg.getDOMNode().className).to.contain( + commonXYProps.xyPlotClassName + ); + + const node = svg.getNode(); expect(node.tagName.toLowerCase()).to.equal("svg"); expect(node.getAttribute("width")).to.equal("600"); expect(node.getAttribute("height")).to.equal("800"); @@ -51,5 +67,22 @@ describe("XYPlot", () => { ); }); - // TODO: TEST MOUSE EVENTS! Use sinon.spy()! + it("triggers event handlers", () => { + const chart = mount(); + expect(chart.props().onMouseMove).not.to.have.been.called; + chart.simulate("mousemove"); + expect(chart.props().onMouseMove).to.have.been.called; + expect(chart.props().onMouseEnter).not.to.have.been.called; + chart.simulate("mouseenter"); + expect(chart.props().onMouseEnter).to.have.been.called; + expect(chart.props().onMouseLeave).not.to.have.been.called; + chart.simulate("mouseleave"); + expect(chart.props().onMouseLeave).to.have.been.called; + expect(chart.props().onMouseDown).not.to.have.been.called; + chart.simulate("mousedown"); + expect(chart.props().onMouseDown).to.have.been.called; + expect(chart.props().onMouseUp).not.to.have.been.called; + chart.simulate("mouseup"); + expect(chart.props().onMouseUp).to.have.been.called; + }); }); diff --git a/tests/jsdom/spec/YGrid.spec.js b/tests/jsdom/spec/YGrid.spec.js new file mode 100644 index 00000000..b7799f8b --- /dev/null +++ b/tests/jsdom/spec/YGrid.spec.js @@ -0,0 +1,75 @@ +import React from "react"; +import * as d3 from "d3"; +import _ from "lodash"; +import { expect } from "chai"; +import { mount } from "enzyme"; + +import { YGrid, YLine } from "../../../src/index.js"; +import { getScaleTicks, getTickDomain } from "../../../src/utils/Scale"; + +describe("YGrid", () => { + const props = { + width: 10, + spacingTop: 10, + spacingBottom: 10, + spacingLeft: 10, + spacingRight: 10, + lineClassName: "ygrid-line-class", + lineStyle: { stroke: "blue" }, + yScale: d3.scaleLinear().domain([0, 100]) + }; + + it("passes props correctly to YLine", () => { + const yGrid = mount(); + const xLines = yGrid.find(YLine); + + xLines.getNodes().forEach(yLine => { + const yLineProps = yLine.props; + + expect(yLineProps.className).to.contain(props.lineClassName); + expect(yLineProps.style).to.equal(props.lineStyle); + expect(yLineProps.spacingTop).to.equal(props.spacingTop); + expect(yLineProps.spacingBottom).to.equal(props.spacingBottom); + expect(yLineProps.spacingLeft).to.equal(props.spacingLeft); + expect(yLineProps.spacingRight).to.equal(props.spacingRight); + expect(yLineProps.yScale).to.equal(props.yScale); + expect(yLineProps.width).to.equal(props.width); + }); + }); + + it("renders the correct amount of YLines given tickCount", () => { + const tickCount = 50; + const xGrid = mount(); + const group = xGrid.find("g"); + + expect(group).to.have.lengthOf(1); + expect(group.getDOMNode().className).to.equal("rct-chart-grid-y"); + + const xLines = xGrid.find(YLine); + const numTicksMade = getScaleTicks(props.yScale, null, tickCount); + + expect(xLines).to.have.lengthOf(numTicksMade.length); + }); + + it("renders the correct amount of YLines given ticks", () => { + const ticks = [0, 25, 50, 100]; + const xGrid = mount(); + const group = xGrid.find("g"); + + expect(group).to.have.lengthOf(1); + expect(group.getDOMNode().className).to.equal("rct-chart-grid-y"); + + const xLines = xGrid.find(YLine); + expect(xLines).to.have.lengthOf(ticks.length); + }); + + it("getTickDomain works as expected", () => { + const ticks = [0, 25, 50, 100]; + + const result = getTickDomain(props.yScale, { ...props, ticks }); + + expect(YGrid.getTickDomain({ ...props, ticks })).to.eql({ + yTickDomain: result + }); + }); +}); diff --git a/tests/jsdom/spec/YTicks.spec.js b/tests/jsdom/spec/YTicks.spec.js new file mode 100644 index 00000000..84763af0 --- /dev/null +++ b/tests/jsdom/spec/YTicks.spec.js @@ -0,0 +1,208 @@ +import _ from "lodash"; +import * as d3 from "d3"; +import React from "react"; +import { shallow, mount } from "enzyme"; +import chaiEnzyme from "chai-enzyme"; +import chai from "chai"; +chai.use(chaiEnzyme()); +const { expect } = chai; + +import { YTicks } from "../../../src/index.js"; + +function expectTicksToExist(wrapper) { + const ticksGroup = wrapper.find("g.rct-chart-ticks-y"); + expect(ticksGroup).to.have.length(1); + expect(ticksGroup).to.have.descendants("line.rct-chart-tick-y"); + return wrapper; +} + +function expectCorrectTickPlacement(wrapper, ticks, scale) { + let tickLines = wrapper.find("line.rct-chart-tick-y"); + expect(tickLines).to.have.length(ticks.length); + tickLines.forEach((line, i) => { + expect(Math.round(+line.prop("y1"))).to.equal(Math.round(scale(ticks[i]))); + }); + return wrapper; +} + +function getLineWidth(line) { + const y1 = +line.prop("x1") || 0; + const y2 = +line.prop("x2"); + return Math.abs(y2 - y1); +} + +describe("YTicks", () => { + const linearScale = d3 + .scaleLinear() + .domain([-5, 5]) + .range([0, 500]); + const timeScale = d3 + .scaleTime() + .domain([new Date(2009, 0, 1), new Date(2010, 0, 1)]) + .range([0, 500]); + const ordinalScale = d3 + .scalePoint() + .domain(["a", "b", "c", "d"]) + .range([0, 300]); + + it("renders a .rct-chart-ticks-y element with tick lines", () => { + expectTicksToExist(shallow()); + expectTicksToExist(shallow()); + expectTicksToExist(shallow()); + }); + + it("uses `tickCount` to determine approx. # of ticks to display on number/time scales", () => { + let wrapper = expectTicksToExist( + shallow() + ); + expect(wrapper.find("line.rct-chart-tick-y")).to.have.length(11); + wrapper = expectTicksToExist( + shallow() + ); + expect(wrapper.find("line.rct-chart-tick-y")).to.have.length(3); + + wrapper = expectTicksToExist( + shallow() + ); + expect(wrapper.find("line.rct-chart-tick-y")).to.have.length(13); + wrapper = expectTicksToExist( + shallow() + ); + expect(wrapper.find("line.rct-chart-tick-y")).to.have.length(5); + }); + + it("uses `ticks` to determine which ticks to show", () => { + const linearTicks = [-3, 2, 4]; + let wrapper = expectTicksToExist( + shallow() + ); + expectCorrectTickPlacement(wrapper, linearTicks, linearScale); + + const timeTicks = [new Date(2009, 4, 10), new Date(2010, 5, 13)]; + wrapper = expectTicksToExist( + shallow() + ); + expectCorrectTickPlacement(wrapper, timeTicks, timeScale); + + const ordinalTicks = ["b", "d"]; + wrapper = expectTicksToExist( + shallow() + ); + expectCorrectTickPlacement(wrapper, ordinalTicks, ordinalScale); + }); + + it("uses `tickLength` to determine tick length", () => { + let wrapper = expectTicksToExist( + shallow() + ); + wrapper + .find("line.rct-chart-tick-y") + .forEach(line => expect(getLineWidth(line)).to.equal(5)); + + wrapper = expectTicksToExist( + shallow() + ); + wrapper + .find("line.rct-chart-tick-y") + .forEach(line => expect(getLineWidth(line)).to.equal(13)); + }); + + it("uses `right` to draw the ticks right of rectangle", () => { + const width = 400; + let wrapper = expectTicksToExist( + shallow() + ); + expect(wrapper.find("g.rct-chart-ticks-y")).to.have.attr( + "transform", + `translate(0, 0)` + ); + + wrapper = expectTicksToExist( + shallow() + ); + expect(wrapper.find("g.rct-chart-ticks-y")).to.have.attr( + "transform", + `translate(${width}, 0)` + ); + }); + + it("draws the ticks above/below line if `placement` is passed", () => { + let wrapper = expectTicksToExist(shallow()); + wrapper + .find("line.rct-chart-tick-y") + .forEach(line => expect(line.prop("x2")).to.be.below(0)); + wrapper = expectTicksToExist( + shallow() + ); + wrapper + .find("line.rct-chart-tick-y") + .forEach(line => expect(line.prop("x2")).to.be.below(0)); + + wrapper = expectTicksToExist( + shallow() + ); + wrapper + .find("line.rct-chart-tick-y") + .forEach(line => expect(line.prop("x2")).to.be.above(0)); + wrapper = expectTicksToExist( + shallow( + + ) + ); + wrapper + .find("line.rct-chart-tick-y") + .forEach(line => expect(line.prop("x2")).to.be.above(0)); + }); + + it("passes className to the ticks", () => { + let wrapper = expectTicksToExist( + shallow() + ); + expect(wrapper).to.have.descendants("line.test-tick-class"); + }); + + it("passes style to the ticks", () => { + const style = { fill: "red" }; + let wrapper = expectTicksToExist( + shallow() + ); + wrapper + .find("line.rct-chart-tick-y") + .forEach(line => expect(line.prop("style")).to.deep.equal(style)); + }); + + it("has a static getMargin method which returns the required outer margin space", () => { + const zeroMargins = { + marginTop: 0, + marginBottom: 0, + marginLeft: 0, + marginRight: 0 + }; + + let margin = YTicks.getMargin({ + tickLength: 10, + position: "left", + placement: "before" + }); + expect(margin).to.deep.equal(_.defaults({ marginLeft: 10 }, zeroMargins)); + margin = YTicks.getMargin({ + tickLength: 10, + position: "left", + placement: "after" + }); + expect(margin).to.deep.equal(zeroMargins); + + margin = YTicks.getMargin({ + tickLength: 10, + position: "right", + placement: "before" + }); + expect(margin).to.deep.equal(zeroMargins); + margin = YTicks.getMargin({ + tickLength: 10, + position: "right", + placement: "after" + }); + expect(margin).to.deep.equal(_.defaults({ marginRight: 10 }, zeroMargins)); + }); +}); diff --git a/tests/jsdom/utils.js b/tests/jsdom/utils.js index 6a4d4371..b2076cbf 100644 --- a/tests/jsdom/utils.js +++ b/tests/jsdom/utils.js @@ -1,6 +1,6 @@ -import * as d3 from 'd3'; -import _ from 'lodash'; -import {expect} from 'chai'; +import * as d3 from "d3"; +import _ from "lodash"; +import { expect } from "chai"; export function expectProps(el, expectedProps) { const props = el.props(); @@ -12,22 +12,33 @@ export function expectProps(el, expectedProps) { export function testWithScales(scaleTypes, callback) { const testScales = { linear: { - scale: d3.scaleLinear().domain([-3, 3]).range([20, 100]), + scale: d3 + .scaleLinear() + .domain([-3, 3]) + .range([20, 100]), testValues: [-1.4, 1.7, 2.8] }, // time: {}, ordinal: { - scale: d3.scalePoint().domain(['a', 'b', 'c', 'd', 'e']).range([0, 100]), - testValues: ['a', 'c', 'e'] + scale: d3 + .scalePoint() + .domain(["a", "b", "c", "d", "e"]) + .range([0, 100]), + testValues: ["a", "c", "e"] } }; scaleTypes.forEach(scaleType => { - if(!_.has(testScales, scaleType)) throw new Error(`${scaleType} is not a valid scaleType for testWithScales`); + if (!_.has(testScales, scaleType)) + throw new Error( + `${scaleType} is not a valid scaleType for testWithScales` + ); }); - const scalesToTest = _.compact(scaleTypes.map(scaleType => testScales[scaleType])); + const scalesToTest = _.compact( + scaleTypes.map(scaleType => testScales[scaleType]) + ); scalesToTest.forEach((scaleInfo, scaleType) => { - callback({...scaleInfo, scaleType}); + callback({ ...scaleInfo, scaleType }); }); -} \ No newline at end of file +}