Unit testing UI components that depend on Cesium?

We’ve got a couple apps that use Cesium (one JS+Backbone, the other Java+GWT). Sadly, neither has any actual unit tests, although we’ve finally been working on some automated integration tests for the Backbone app. I’ve been prototyping a potential rewrite of the GWT app in modern JS (Webpack+ES6+React), and currently have a basic unit testing setup in place using Mocha (test runner), Chai (assertions), Enzyme (React component testing), and JSDOM (for actually “rendering” components under Node, without needing a browser). I’ve also got Webpack set up to load Cesium using a variation on the “pre-built” approach described at https://github.com/mmacaula/cesium-webpack (and I may try to document those changes when I have a chance).

At the moment, I’ve got the Mocha setup being done separately from all the Webpack stuff, so Mocha uses Babel to do the transpiling, but then ignores stuff Webpack would load like CSS and images. This worked fine, until I tried running my test setup and it pulled in my initial React component that requires Cesium. I see one error which I may or may not be able to work around, but this actually brings up some larger questions about how to approach testing things that depend on Cesium. I know I’ve also seen suggestions that offline tests with Mocha should be doing by just using Webpack to do an actual build with test-specific entry points and running Mocha against the bundled output, as that would centralize the load/alias/whatever logic. I may give that a shot soon, but trying to see how far I can get with this.

First, the actual error I see at the moment. Because Cesium embeds a copy of Knockout, and depends on Require to load it, Node wound up reporting “Error: Cesium missing ThirdParty/knockout-3.2.0”. I figure there’s probably some way to work around that using some hack-ish approach to modifying Node’s built-in “require” function, but haven’t gotten that far yet. (Any suggestions welcome.)

So the larger question is really this: what is an appropriate way to approach unit testing components that depend on Cesium? This would include, say, a top-level component that is responsible for actually initializing and rendering a Cesium.Viewer widget, or view classes which are responsible for creating and destroying Cesium primitives as part of their lifecycle (we have Backbone Views that render Cesium primitives in our first app, and I’m figuring I can do the same with React Components in the second app). How would I handle having Cesium as a dependency for a given component? Is there a good approach for mocking out Cesium? Can Cesium even do anything useful under Node, particularly with JSDOM or similar, or would I be restricted to purely testing/running code that uses it in an actual browser?

I guess my questions are being driven by a few intertwined thoughts. First is my lack of actual practical experience with writing unit tests, so I’m still mostly trying to figure out what sorts of behavior and tests to write in the first place. The second is trying to put together a specific build configuration using the tooling I’ve selected, particularly Webpack and Cesium. The third is wanting to be able to run tests offline under Node using Mocha, without having to use a real browser or even a headless browser like PhantomJS, for simplicity of dependencies and speed.

I would appreciate any thoughts, suggestions, or comments people have on these issues.

After several hours of groveling through docs, articles, issues, source, and error messages, I think I have managed to put together just about everything I actually wanted.

I decided to try actually using Webpack to generate a “test” build rather than trying to configure Babel as a separate compiler for Mocha to use. I seem to have successfully come up with a configuration that minimizes the amount of work that Webpack has to do, so that a build of the “test” target (which admittedly only has 4 test files and a dozen tests) takes 2 seconds. That outputs a bundle of the test code and required app code, which I can then pass into Mocha.

I ran into a number of issues with React doing tests of its environment and thinking it wasn’t actually in a DOM, which I was able to resolve by very carefully ordering the setup code in the helper script I’m using to initialize my Mocha environment. In particular, I had to ensure that “document” and “navigator” were available globally before I ever imported anything React-related in that file.

Using the Enzyme library, I was able to “mount” a component that creates a Cesium.Viewer widget. Sadly, Cesium then complained that WebGL wasn’t available. The JSDOM library looks like it can detect if the “node-canvas” library is available and use that to help implement its fake Canvas element, but I don’t think that node-canvas supports WebGL. There’s also a “headless-gl” project out there, but doesn’t look like it does anything Canvas-related.

However, I also did try creating a React component that simply creates a Cesium primitive, like this:

import React, {Component} from ‘react’;
import Cesium, {Billboard, BillboardCollection} from “cesium/Cesium”

import fireflyIcon from “styles/Firefly.png”;

export default class CesiumBillboard extends Component {
componentDidMount() {
this.billboards = new BillboardCollection();
}

addBillboard() {
    this.billboards.add({
        position : new Cesium.Cartesian3(1.0, 2.0, 3.0),
        image : fireflyIcon
    });
}

render() {
    return null;
}

componentWillUnmount() {
    this.billboards.destroy();
}

}

``

and then instantiate it and use it in a test:

it(“Can add a billboard”, () => {
const wrapper = mount();

    let inst = wrapper.instance();
    inst.addBillboard();

    expect(inst.billboards.length).to.equal(1);
})

``

So it would seem that as long as I just don’t try to actually instantiate a Scene in my tests or anything, I can write tests that exercise React+Cesium components entirely offline.

I will see if I can maybe get this test project cleaned up, documented, and published in the near future. Seems like a pretty useful set of capabilities to have around, and hopefully someone else can make use of what I’ve learned.

I’d still be interested in any thoughts people have to offer on approaches for testing code that actually uses Cesium . I have read the main Cesium documents on how the Cesium internals are tested, but seems like testing code that uses Cesium is another matter.

Hello.

Can you share any details about making a test Cesium build with Babel?