Unit test in Webix Jet

Hi,

I have two main questions for unit test in Webix Jet.

  1. How to use Mocha tests in Webix-Jet 2.1.2? Where can I get unit tests sample codes for this version?

1-1. I try to use suggested Mocha tests from jet-start/package.json at tests · webix-hub/jet-start · GitHub
1-2. I change dependencies “webix-jet” ^1.6.1 to ^2.1.2
1-3. After executing npm run test, I get “TypeError: Cannot read property {current|count|queryView} of undefined”

  1. In my design, I use webix.ajax() to interact with data. How to generate mock function or data in unit test for Webix view? Which unit test package could be integrated with Webix-Jet 2.1.2. I need some sample codes for this.

Thanks

  1. Not sure if I understood your use case correctly, so correct me if i am wrong.

If you want to imitate async data, you can do something along the lines of:

// models/records.js
export const data = new webix.DataCollection({ 
	url: () => {
		return webix.promise.resolve([
			{ id:1, title:"The Shawshank Redemption", year:1994, votes:678790, rating:9.2, rank:1},
			{ id:2, title:"The Godfather", year:1972, votes:511495, rating:9.2, rank:2},
			{ id:3, title:"The Godfather: Part II", year:1974, votes:319352, rating:9.0, rank:3},
			{ id:4, title:"The Good, the Bad and the Ugly", year:1966, votes:213030, rating:8.9, rank:4},
			{ id:5, title:"My Fair Lady", year:1964, votes:533848, rating:8.9, rank:5},
			{ id:6, title:"12 Angry Men", year:1957, votes:164558, rating:8.9, rank:6}
		]);
	}
});

To test that the data are loaded (similarly to this test), you could check data count:

import {data} from "models/recordsasync";
describe("model: records async", function() {
	it("has some data", function() {
		data.waitData.then(() => {
			expect(data.count()).to.be.above(0);
		});
	});
});

If you load data into some other Webix view (meaning not a collection, but DataTable or List), you can test it in the same way (use waitData).

Hi,

  1. about the errors in the tests: there is the issue with view.render method, it expects the second parameter url: IRoute, and giving them “data” and “top” accordingly seems to resolve this and all tests pass (tried with Jet 2.1.2 and 2.1.3, which is the latest). There were changes to render method since 1.6. Thanks for pointing this out.

Thank you for your suggestion.
I have another question.

I try to use this.setService in init() in myapp.js

Later, I attempt to use app.getService(“serviceName”) in unit test.

It’s “undefined” and failed to getService in unit test.

JetApp does not have the init() method. The example in the Jet Book shows how to create services in views, that’s why there it is in init(). In JetApp, you would do all that work (like creating services, setting config, etc) in its constructor:

// myapp.js
export default class MyApp extends JetApp{
	constructor(config){
		// ...all the code from jet-start

		this.setService("serviceName", {
			getName(){
				return "I am a service!";
			}
		});
	}
}

We create services the same way in our complex widgets.

I guess we should add something like this code sample to Jet Book.

I think it’s better to add the above into Jet Book.

For ajax in mocha unit test, I try to use webix.ajax().get() (webix imported) or myapp.webix.ajax().get(), and then they don’t work for me.
The API is called, but .then() isn’t invoked, which means I can’t get the result data.

How to use webix ajax in unit test code?

I have added it to jet Book.

webix is not stored in JetApp instances, but it’s stored in JetView instances. You can refer to it as a global variable in these tests due to the setup.

I am sorry for some misinformation about async data in tests. Seems that Mocha does not work with network and you have to add something else to imitate network activity. For example, Sinon. There’s also the issue with asynchronisity in Mocha: you must call done when testing is done (alternatives would be to return a promise or to use async/await).

For imitating webix.ajax() request that gets some data, I wrote this very simple example using sinon.fake:

var chai = require("chai");
var expect = chai.expect;

var sinon = require("sinon");

const data = [
	{ id:1, title:"The Shawshank Redemption", year:1994, votes:678790, rating:9.2, rank:1},
	{ id:2, title:"The Godfather", year:1972, votes:511495, rating:9.2, rank:2},
	{ id:3, title:"The Godfather: Part II", year:1974, votes:319352, rating:9.0, rank:3},
	{ id:4, title:"The Good, the Bad and the Ugly", year:1966, votes:213030, rating:8.9, rank:4},
	{ id:5, title:"My Fair Lady", year:1964, votes:533848, rating:8.9, rank:5},
	{ id:6, title:"12 Angry Men", year:1957, votes:164558, rating:8.9, rank:6}
];

describe("model: records async", function() {
	before(function(){
		sinon.replace(webix, "ajax", sinon.fake.returns(Promise.resolve(data)));
	});

	after(function () {
		sinon.restore();
	});

	it("has some data", function(done) {
		webix.ajax("some/path").then(data => {
                        // since my fake returns a ready array, no need to call .json() as you would with the real webix.ajax()
			expect(data.length).to.be.above(0);

			done();
		});
	});
});

For more detailed testing, you can also create a fake server (Sinon docs).

Hi, I have checked that mocha unit test supports network activity.
The following code is modified from jet-start/top.test.js at tests · webix-hub/jet-start · GitHub and executed in webix 6.0.9 and webix-jet 2.1.2

The test case “xhr ajax test” will pass, and however “can be initialized” is failed.
For view.webix.ajax().get(url), it invokes the API server successfully, but it didn’t execute then()

var chai = require("chai");
var expect = chai.expect;

import MyApp from "myapp";
import View from "jet-views/top";

let temp, app, view;
describe("/top", function() {

	before(function(){
		temp = document.createElement("DIV");
		document.body.appendChild(temp);
		app = new MyApp({});
		app.render(document.body);
	});

	it("xhr ajax test", function(done) {

		var xhr = new XMLHttpRequest();
		xhr.open("GET", url, true);

		xhr.onload = function(){
			console.log(xhr.responseText);
			if(xhr.readyState === 4){
				done();
			}
		}

		xhr.send();

	});


	it("can be initialized", function(done) {

		view = new View(app, "");
		view.render(temp, "test");

		view.webix.ajax()
		.get(url)
		.then((data)=>{
			console.log(data.json());
			done();
		});

	});

	after(function(){
		document.body.removeChild(temp);
	});
});

Hi, yes, you are right, sorry for misinformation. After some more investigation I noticed that the problem is with webix.promise that is used to create a promise that is returned by webix.ajax. Webix promise is a version of this lib promiz/promiz.js at master · Zolmeister/promiz · GitHub .

I can confirm that it is a bug. I changed the code of webix.ajax.get so that it used the native Promise, and it works in Mocha. As an alternative to that right now I can recommend using callbacks. This will work in Mocha:

webix.ajax()
	.get("https://docs.webix.com/samples/server/packages", (text, data) => {
		expect(data.json().length).to.be.above(0);
		done();
});

Thank you very much for your question :slight_smile:

I try to import a view composed of gantt layout for unit test. The gantt layout is with override: new Map([[gantt.services.Backend, ganttBackend]]). Customizing Gantt of UI Complex Widgets, Gantt Webix Docs

When I just import the gantt layout, there is a ReferenceError saying “gantt” is not defined in ganttBackend. How can I do in the customized service class?

To access services and views, you have to import import * as gantt from "@xbs/gantt"; (or wherever gantt sources are stored in your project, in my case they are in node_modules/@xbs/gantt).