What are unit testing strategies for D3JS? - unit-testing

I am completely new to D3JS and would like to understand the testing strategies for D3 JS.
To elaborate little more on question - consider I have a simple page that shows a line graph using a TSV file.
Java Script Code:
function LineManager() {}
function LineProperties() { // Line Properties }
LineManager.prototype.draw = function(properties) {
// D3 code to draw a line with the given properties.
}
I am not able to think of test cases to be considered for writing unit tests. Here is a sample test that I wrote ..
it("should throw an exception if line graph properties are not set.", function() {
expect(lineManager.draw.bind(lineManager)).toThrow("Line Graph properties not set");
});
it("It should have single line chart", function() {
lineManager.draw(properties);
expect(lineManager.countLines()).toEqual(1);
});
I have written unit tests to make sure the TSV file is getting generated correctly. But does it make sense to write a unit test to see if the data is getting rendered correctly? Isn't that more of a d3js unit test rather than unit test for my function?
So my question is - what tests should be considered for charts generated by d3js?

I think I got the answer to my own question. Will try to explain it here.
It is not possible to validate whether the graph is plotted correctly by JS function written using D3JS. For this we may have to use Phantom.js or similar framework as mentioned by Chrisopher. I was not worried about making sure D3JS is plotting graph correctly, as any ways it is D3JS functionality and my code can safely assume D3JS is doing its work.
My worry is more of whether the data passed to D3JS is correct and as per my requirement. It is very much possible to make sure the properties of the graph are set correctly by creating Spy objects. I am providing a sample unit test covering test cases for a JS code plotting a Circle using D3JS.
CircleManager.js
function CircleManager() {};
CircleManager.prototype.draw = function(radius) {
var svg = d3.select("body")
.append("svg");
svg.attr("width", 100)
.attr("height", 100);
var circle = svg.append("circle");
circle.style("stroke", "black")
.style("fill", "white")
.attr("r", radius)
.attr("cx", 50)
.attr("cy", 50);
};
CircleManagerSpec.js
describe("draw", function() {
it("Constructs an svg", function() {
var d3SpyObject = jasmine.createSpyObj(d3, ['append', 'attr']);
// Returns d3SpyObject when d3.select method is called
spyOn(d3, 'select').andReturn(d3SpyObject);
var svgSpyObject = jasmine.createSpyObj('svg', ['append', 'attr', 'style']);
// Returns svgSpyObject when d3.select.append is called.
d3SpyObject.append.andReturn(svgSpyObject);
d3SpyObject.attr.andCallFake(function(key, value) {
return this;
});
svgSpyObject.append.andReturn(svgSpyObject);
svgSpyObject.attr.andCallFake(function(key, value) {
return this;
});
svgSpyObject.style.andCallFake(function(key, value) {
return this;
});
var circleManager = new CircleManager();
circleManager.draw(50);
expect(d3.select).toHaveBeenCalledWith('body');
expect(d3SpyObject.append).toHaveBeenCalledWith('svg');
expect(svgSpyObject.attr).toHaveBeenCalledWith('r', 50);
expect(svgSpyObject.attr).toHaveBeenCalledWith('width', 100);
expect(svgSpyObject.attr).toHaveBeenCalledWith('height', 100);
expect(svgSpyObject.style).toHaveBeenCalledWith('stroke', 'black');
expect(svgSpyObject.style).toHaveBeenCalledWith('fill', 'white');
});
});
Hope this helps.

I think you should consider this: http://busypeoples.github.io/post/testing-d3-with-jasmine/
And it really seems to make sense. I have read the others' answers but I am little bit disagree with them. I think we not only check if right function is called or not but we can check much more than that. Checking only some function call are good at unit testing level but not enough. Such test cases written by developer will be based on developer's understanding like these functions are called or not. But whether these methods should be called or not, this thing can be only checked by going at another level because unlike other work, here are code is making something not returning something that can be just checked and make sure everything is correct.
We obviously don't need to check whether D3 is doing its work correctly or not. So we can use D3 inside our testing code. But D3 renders SVG and we can check things like if svg have elements where expected. Again it is not going to test whether SVG is showing and rendering properly or not. We are going to check if SVG have elements which are expected and they are set as expected.
For example:
If this is bar chart, we can check the number of bars. As in example in above link here it is check that.
// extend beforeEach to load the correct data...
beforeEach(function() {
var testData = [{ date: '2014-01', value: 100}, { date: '2014-02', value: 140}, {date: '2014-03', value: 215}];
c = barChart();
c.setData(testData);
c.render();
});
describe('create bars' ,function() {
it('should render the correct number of bars', function() {
expect(getBars().length).toBe(3);
});
it('should render the bars with correct height', function() {
expect(d3.select(getBars()[0]).attr('height')).toBeCloseTo(420);
});
it('should render the bars with correct x', function() {
expect(d3.select(getBars()[0]).attr('x')).toBeCloseTo(9);
});
it('should render the bars with correct y', function() {
expect(d3.select(getBars()[0]).attr('y')).toBeCloseTo(0);
});
});
// added a simple helper method for finding the bars..
function getBars() {
return d3.selectAll('rect.bar')[0];
}
Some people probably gonna say that we are going to use D3 inside testing code? Again we should remember that purpose of test writing here is not to test D3 but our logic and SVG code that is compiled in response to our code.
This is just a way and jasmine is something that is helping us in writing test, you can also go into more detail and in different scenarios. You can make domain and check datapoints width height to cross check if they result into data which were given to render.
I think I am clear if not then check this link : http://busypeoples.github.io/post/testing-d3-with-jasmine/
Here write of this article have explained things in detail with how you can use jasmine.
Also I think I am still gone into detail. If only unit testing is required at different js functions level then there are a lot more things which can be tested without going into elements detail.

Testing strategy
The strategy I end up using to test d3.js code is to create helper functions to manage my data and settings. I then unit test these functions. So for charts I would check every functionality dealing with data, every function to set width, legends etc...
Concerning drawing functions it can get trickier but with testing frameworks such as buster.js it can be quite easy to implement these too. A good way of testing a chart would be to count the number of bars/lines in the page, check that legends are printing etc.
I would not try to check that the chart is visually the same because visually checking that the end result is the same is easiest. However, when writing the drawing functions, one should be very attentive to what happens on updates (will changing the data draw twice as many lines? are selectors right? ...)
Javascript testing
A great book on javascript testing is: Test Driven Javascript Development. It provides lots of examples and strategies to test javascript code. Most of them can be directly applied to d3.js code.
Tools
I recently looked for solutions for unit testing d3.js code and I ended up using the following tools:
buster.js
Buster.js is a very complete framework for unit testing javascript code in multiple browsers.
phantom.js
Phantom.js is a headless WebKit scriptable with a JavaScript API.
This means that it makes it easy to run automated tests on javascript without needing to use browsers such as chrome, safari etc..
EDIT: I would now use jasmine for unit testing and selenium (through the Saucelabs service maybe) for end to end testing.

Probably worth mentioning Jest snapshot testing. Jest/snapshots are popular for React UI components, as they're also difficult to test. With D3 you could generate an SVG take a snapshot and verify as your codebase evolves that you continue to generate the same output.
function makeChart(id, dataset) {
const chart = d3.select(id)
.append("svg")
.selectAll("circle")
.data(dataset)
.enter().append("circle")
.style("stroke", "gray")
.style("fill", "black")
.attr("r", 40)
.attr("cx", 50)
.attr("cy", 20);
return chart;
}
it('renders correctly', () => {
const myChart = makeChart('#example', [1,2,3])
expect(myChart.node()).toMatchSnapshot();
});
This test is untested
A snapshot can be any output a string "Foo Bar" a JSON object {foo: "bar"} etc.
Basically you have to run a test once that contains .toMatchSnapshot. Jest will then manage the generation and store a copy that it'll compare in future tests.
The concept is similar to VCR in Ruby testing. Record and replay.

Related

Vue Mocha test: wrapper.setProps({}) does not update nested Components props

I am the developer of this Vue.js Plugin and am currently working on the test for v1.0.0, using already written tests for older versions with some adjustments.
Scenario
Test the components with the following structure:
// receives props and passes through
VueEllipseProgress
// receives props, adds new and passes through
EpCircleContainer
// receives props and do main SVG rendering
CircleProgress
Use Factory function:
// this is the top level VueEllipseProgress component
import Container from "../../../src/components/VueEllipseProgress.vue";
import Circle from "../../../src/components/Circle/CircleProgress.vue";
const factory = propsData => {
return mount(Container, {
propsData: {
...propsData
}
});
};
const wrapper = factory({...})
Use wrapper.setProps() in the test to apply new props. Test, how changed props affect the rendering of SVG elements on the other end. You can see the whole code on GitHub.
Problem
wrapper.setProps() updates the props of the VueEllipseProgress (top level) correctly and wrapper.vm.$props has the expected values. But the props of CircleProgress component remain unchanged, HTML still not updated. This leads to test failures.
it("do some test", () => {
/* do some test here, all is fine */
wrapper.setProps({ someProp}); // set new props
wrapper.vm.someProp; // updated
circleWrapper.vm.someProp; // still old
// fails!!!
expect(circleWrapper.element.getAttribute("someProp")).to.equal(someProp);
});
Here are more code details related to above example.
Note, that the plugin works correctly live and all props are reactive.
The test worked for earlier versions of my plugin. In the meantime i have updated #vue/cli to version 4.x.x. Maybe the failures are related to this update, but I couldn't find any information in the release notes that could confirm this.
This is not the direct solution, more a tip to avoid the problem. In my components, I use v-binde="$props" to propagate the props to subcomponents. However, this can cause issues with jsdom, like in my case.
I ended up with refactoring all my tests by testing each komponent directly, avoiding the need of nested structure and props propagation (like unit tests are supposed to be).

Unit testing ag-grid in Angular 2

Has someone worked on unit testing ag-grid components in Angular 2?
For me, this.gridOptions.api remains undefined when the test cases run.
Sorry to be a little late to the party but I was looking for an answer to this just a couple of days ago so wanted to leave an answer for anyone else that ends up here. As mentioned by Minh above, the modern equivalent of $digest does need to be run in order for ag-grid api's to be available.
This is because after the onGridReady() has run you have access to the api's via the parameter, looking like so. This is run automatically when a component with a grid is initialising. Providing it is defined in the grid (gridReady)="onGridReady($event)"
public onGridReady(params)
{
this.gridOptions = params;
}
This now means you could access this.gridOptions.api and it would be defined, you need to re-create this in your test by running detectChanges(). Here is how I got it working for my project.
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
fixture.detectChanges(); // This will ensure the onGridReady(); is called
This should inturn result in .api being defined when running tests. This was Angular 6.
Occasionally the test may have to perform an await or a tick:
it('should test the grid', fakeAsync( async () => {
// also try tick(ms) if a lot of data is being tested
// try to keep test rows as short as possible
// this line seems essential at times for onGridReady to be processed.
await fixture.whenStable();
// perform your expects...after the await
}));
If you are using ag-grid enterprise make sure to include in your test file import 'ag-grid-enterprise'; otherwise you will see console errors and gridReady will never be called:
Row Model "Server Side" not found. Please ensure the ag-Grid Enterprise Module #ag-grid-enterprise/server-side-row-model is registered.';
It remains undefined because the event onGridReady is not invoked yet. Im not sure about Angular 2 because im using angularjs and have to do $digest in order to invoke onGridReady.

Good example of using BDD language to write unit tests?

I'm a big fan of BDD for integration tests and have started looking at using them from unit tests as well. From other questions (e.g. this one 1), I can see that people generally consider it acceptable to write BDD style unit tests. However, I haven't seen any examples of unit tests using BDD language. Seeing some concrete examples would help me get my head around it much better.
I'm wondering how to use BDD when the test is examining low level system behaviour that a user would not experience. For an integration/view test, I'd do something like this:
describe('Given that an author is using the question editor with a choice matrix question open ', function () {
describe('When the author clicks the 'Allow Multiple Responses' switch', function () {
it('Then the question preview should change from radio buttons to checkboxes', function () {
expect(....);
});
});
});
But what about if I'm testing the functionality of a low level method? Is it an anti-pattern if I'm trying to test a low level unit that a user would never touch it? For example, if I want to use Jasmine to test the functionality of a method called isCellShadedByAuthor(), my best guess is to do something like this:
describe("Given that the cell is in the response area not on the author side", function () {
it("When the cell is an author shaded cell, then isCellShadedByAuthor should return true", function () {
expect(isCellShadedByAuthor(1, 3)).toBeTruthy();
});
));
I guess another way to approach this situation is to try to elevate the test to a view test where I'd assert based on the presence of a CSS class rather than directly asserting on the return value of isCellShadedByAuthor(). This would reduce the coupling of the test to the implementation details.
For example, I could do ​
describe("Given that the cell is in the response area not on the author side", function () {
it("When the user hovers over an author shaded cell, then the cell should have the hover class", function () {
var cell = $('shading-cell[data-attribute-x="1"][data-attribute-y="1"]);
expect(cell.hasClass('hover-disabled')).toBeTruthy();
});
));
I'm not sure if you question pertains purely to JavaScript, but I have certainly used BDD unit tests for Java projects at previous employers. We made use of the BDDMockito class in the Mockito library.
We actually created a very simply BDD unit test template in our IDE that we all shared.
public void shouldDoFooOnBar() {
//given (perform setup here)
<code to define state of system>
//when
<single call to code under test>
//then
<code to assert expectations>
}
We found this gave our tests a nice consistent structure that was easy to read.
Here is a concrete example from Mockito:
public void shouldBuyBread() throws Exception {
//given
given(seller.askForBread()).willReturn(new Bread());
//when
Goods goods = shop.buyBread();
//then
assertThat(goods, containBread());
}
It is worth mentioning that we were also using BDD at the integration test level, but for this we were using FitNesse.

Detect if a new window was opened in an Ember test

I dont know if this is even possible but here is my issue :
I'm doing some javascript testing in my Ember.js application and at some point, I have a button/link that opens a new window to a partner website, when certain conditions are met.
Now I'm looking for a way to test that behaviour in my karma/qunit tests but I haven't the slightest idea of how to do that. Any pointer would be appreciated !
document.write('<div id="test-app"></div>');
App.rootElement = '#test-app';
App.setupForTesting();
App.injectTestHelpers();
module("Services");
test("Access services", function () {
visit("/p/2/i/services").then(function () {
click('#MyService').then(function () {
// What should I do here ?
});
});
});
My first recommendation would be to abstract the window.open functionality into a module, so the app just accesses a single interface when it wants to open a window. It shouldn't care HOW the module does it, its only concern is that it calls the module's window open method with the correct parameters.
The way you confirm that it's calling the window open method with the correct parameters is by using method stubs for your tests by using something like Sinon.js (http://sinonjs.org/). This will allow you to stub your window open method, and run assertions that it was called a certain number of times and with certain parameters. It's a little hard to get set up the first time, but it's definitely a necessary evil to thoroughly testing your app.

Unit testing for Jfreecharts

I am constructing a simple linechart using JFreechart API.. Can anyone let me know how to unit test it using mockito. I am still kind of new to do unit testing framework. Dont really know how it works
public LineChart(String applicationTitle, String chartTitle) {
super(applicationTitle);
// Create the dataset
CategoryDataset dataset = new DataSet().createDataLineSet();
JFreeChart chart = createChart(dataset, chartTitle);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(CHART_WIDTH,
CHART_HEIGHT));
setContentPane(chartPanel);
}
/**
* Creates a sample chart
*
* #param dataset
* ,the chartTitle
*
* #return The chart.
*/
public JFreeChart createChart(CategoryDataset dataset, String chartTitle) {
// TODO Auto-generated method stub
// create the chart
JFreeChart chart = ChartFactory.createLineChart(chartTitle, // chart
// title
categoryAxisLabel, // category axis label
valueAxisLabel, // value axis label
dataset, // data
PlotOrientation.VERTICAL, // chart orientation
true, // include legend?
true, // include tooltips?
false // URLs?
);
return chart;
}
The way you've structured it, this is a particularly hard class to unit test, and I'm not sure how much value unit testing would provide. Is this code for a school or work project with a "unit test all your code" directive?
First, a clarification based on your tags: Mockito is not a unit testing framework.
junit is a unit testing framework that allows you to write classes with methods that exercise classes. Using exceptions, as well as calls to Assert.assertEquals, Assert.assertTrue, and Assert.fail (for instance) you can write tests with minimal boilerplate. Reading JUnit's Getting Started page may help.
mockito is a mocking framework, which allows you create mocks and stubs of objects and verify that you're system under test is interacting with its collaborators correctly. Though it's preferable to unit test just by checking the return value of a method call or the state of the system after your test, certain classes require interaction with external systems. The first few numbered items of the Mockito documentation may help.
At least three things make your class hard to test using mocks and JUnit:
Your system under test is directly calling constructors. This gives you very little opportunity to substitute in simpler implementations or mocks for test.
The collaborator you're interacting with (JFreeChart API) is designed for GUIs. It can be hard to test GUI-oriented classes in a headless, reproducible way, which are two typical aspects of unit tests.
The collaborator is third-party software, which can be dangerous to mock. Mocking relies on some implementation details (like whether methods are public or final) that can be dangerous for code that's not directly under your control.
Remember also that it is an anti-pattern to test the implementation—unit tests are designed to check that your code produces the correct results. Looking at the code that you posted, I'm not sure what I would test there.
On the other hand, if you have a separate part of the project that loads and processes numeric data to feed into your chart, it would be very straightforward and useful to produce a JUnit test that takes in data from a sample file, runs it through the loader/processor you write, and ensures that it produces the correct numbers that you've worked out and confirmed by hand. The continued passing of that test is some guarantee that your code still works as expected, even if the implementation of your loader/processor were to change.