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.
Related
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.
I try to atomize my tests for a given UI5 application. Therefore I created a folder under WebContent called test-resources. In that folder I placed two files for first tests.
First file: experimental.qunit.html that contains some first working unit test code.
Second file: experimental.opa.html which contains an example code from the documentation.
The testing part looks like this:
opaTest("Should find a Button with a matching property", function(Given, When, Then) {
// Act
Given.iStartMyAppInAFrame("index.html");
When.waitFor({
viewName : "view.master.Master",
controlType : "sap.m.Button",
matchers : new sap.ui.test.matchers.PropertyStrictEquals({
name : "icon",
value : "sap-icon://show"
}),
success : function (aButtons) {
debugger;
ok(true, "Found the button: " + aButtons[0]);
},
errorMessage : "No button with property icon equal to sap-icon://show"
});
Then.waitFor({
// not implemented
});
Then.iTeardownMyAppFrame();
});
First of all I assume that I can search a button also with icon property.
Second assumption is, that viewName is the name and folder of the view file? In the app, the view is the master view of a split app.
I start the test like this:
* In Eclipse mark the project and choose run as "Web App Preview"
* Than of course I see my normal app
* I replace the index.html part with test-resoruces/experimental.opa.html
* Now I can see the test and my app is shown in an iframe
But:
1. The button selection is not working, anyone an idea what's wrong?
2. If I change the html code I have to restart the "Web App Preview" all the time, a reload seems not working. Is there a "better" way to run the tests after updating test code?
The app itself is defined as a component, and the main view is a SplitApp xml file that contains nothing than:
<mvc:View
xmlns:mvc="sap.ui.core.mvc"
displayBlock="true"
xmlns="sap.m">
<SplitApp id="idAppControl" />
</mvc:View>
Meanwhile I detect the problem and fixed it. My syntax of PropertyStrictEquals was wrong.
The restart problem (of Web App Preview) still exists.
I also detected a helpful example:
https://openui5beta.hana.ondemand.com/test-resources/sap/m/demokit/cart/test/BuyProductJourney.qunit.html
It is mentioned here:
http://scn.sap.com/community/developer-center/front-end/blog/2014/10/16/javascript-based-integration-tests-for-sapui5-apps-with-opa
(Have a look at the testing Tutorial in the developper guide)
First of all, in your example you are mixing the levels of abstraction. Directly in your jurney (the order of steps for your tests) there should not be any code like waitFor(), because that is page specific code. So you should create pages, on where your actual arrangements, actions and assertions take place. In the jurney you only call them. like this (source):
opaTest("Should see the post page when a user clicks on an entry of the list", function (Given, When, Then) {
// Arrangements
Given.iStartMyApp();
//Actions
When.onTheWorklistPage.iPressOnTheItemWithTheID("PostID_15");
// Assertions
Then.onThePostPage.theTitleShouldDisplayTheName("Jeans");
});
Those objects onTheWorklistPage and onThePostPage are your actual test steps, wher you search for objects and trigger a click or check the displayed text you create them like that:
Opa5.createPageObjects({
onTheWorklistPage: {
baseClass: Common,
actions: {...},
assertions: {...}
}
})
Now in those actions and assertions you put your waitFor() to get elements and do something with them. This function is described in the API
PS: Your question is very unstructured and I am not shure if I answered your question, if not, please comment.
I'am new to Extjs5 and trying to run jasmine unit test cases with karma-runner. Although am sucessfully able to do that fro Ext4.2 application but same process is not working for Extjs5.
I have goggled it but didn't got any useful link
If anyone have already executed for Ext5 app please share the code.
Any help is highly appreciated.
Thanks
Tapaswini
The trick is to allow the required ExtJS classes to properly load before you start your test.
Make sure you include the following in your karma.conf.js
// We need to add an element with the ID 'appLoadingIndicator' because [app.js].launch() is expecting it and tries to remove it
// Karma normally starts the tests right after all files specified in 'karma.config.js' have been loaded
// We only want the tests to start after Sencha Touch/ExtJS has bootstrapped the application
// 1. We temporary override the '__karma__.loaded' function
// 2. When Ext is ready we call the '__karma__.loaded' function manually
var karmaLoadedFunction = window.__karma__.loaded;
window.__karma__.loaded = function () {
};
bootstrapExtJS(); // Create this function to add anything that is not included in your class definition requires and you need to require explicitly
Ext.onReady(function () {
window.__karma__.loaded = karmaLoadedFunction;
window.__karma__.loaded();
});
Let me know if it works for you.
I'm testing an relatively large Ember application (http://wheelmap.org/map) with QUnit and having problems with debounced calls e.g. changing the url to have a permalink of a map view inside the app or doing a manual AJAX request while testing.
I followed the documentation at http://emberjs.com/guides/testing/integration/
Now when I reset the application state by calling App.reset() in the module setup it resets all bindings, etc. to variables and dependant controllers.
module('Map', {
setup: function() {
App.reset();
}
});
This seems to be good to have a clean working environment, but leads to errors where variables are accessiable by Ember.set and Ember.get e.g. this.get('controllers.toolbar'):
Cannot call method 'set' of null
So the first test allways runs great, but further tests break because of debounced function calls from the first test. So what I think I have to do is stop this debounced calls somehow.
Other options would be checking if all needed variables are set in this function calls. But this seems to be cumbersome when adding conditions only for testing.
What do you think?
Thank you in advance!
I found the answer by searching through the RunLoop source files:
Ember.run.cancelTimers()
It's not part of the documentation. Maybe a problem of poor documentation or not beeing part of the public API.
Now I just call it in the module test teardown function:
module('Map', {
setup: function() {
// ...
},
teardown: function() {
Ember.run.cancelTimers()
}
});
We ran into a similar problem and decided to disable debounce during testing.
You can check if in testing mode using if(Ember.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.