瀏覽代碼

initial tests integration

Raanan Weber 7 年之前
父節點
當前提交
67be271278

+ 58 - 0
Tools/Gulp/gulpfile.js

@@ -1037,6 +1037,64 @@ gulp.task("tests-unit", ["tests-unit-transpile"], function (done) {
     server.start();
 });
 
+/**
+ * Transpiles viewer typescript unit tests. 
+ */
+gulp.task("tests-viewer-unit-transpile", function (done) {
+    //var tsProject = typescript.createProject('../../Viewer/tests/unit/tsconfig.json');
+
+    //var tsResult = gulp.src("../../Viewer/tests/unit/**/*.ts", { base: "../../Viewer/" })
+    //.pipe(tsProject());
+
+    /*tsResult.once("error", function () {
+        tsResult.once("finish", function () {
+            console.log("Typescript compile failed");
+            process.exit(1);
+        });
+    });*/
+
+    let wpBuild = webpack(require('../../Viewer/tests/unit/webpack.config.js'));
+
+    return wpBuild
+        .pipe(through.obj(function (file, enc, cb) {
+            // only pipe js files
+            const isJs = /\.js$/.test(file.path);
+            if (isJs) this.push(file);
+            cb();
+        }))
+        .pipe(rename("tests.js"))
+        .pipe(gulp.dest("../../Viewer/tests/unit/build/"));
+});
+
+/**
+ * Launches the KARMA unit tests in phantomJS.
+ * (Can only be launch on any branches.)
+ */
+gulp.task("tests-viewer-unit-debug", ["tests-viewer-unit-transpile"], function (done) {
+    var kamaServerOptions = {
+        configFile: __dirname + "/../../Viewer/tests/karma.conf.js",
+        singleRun: false,
+        browsers: ['Chrome']
+    };
+
+    var server = new karmaServer(kamaServerOptions, done);
+    server.start();
+});
+
+/**
+ * Launches the KARMA unit tests in phantomJS.
+ * (Can only be launch on any branches.)
+ */
+gulp.task("tests-viewer-unit", /*["tests-viewer-unit-transpile"],*/ function (done) {
+    var kamaServerOptions = {
+        configFile: __dirname + "/../../Viewer/tests/karma.conf.js",
+        singleRun: true
+    };
+
+    var server = new karmaServer(kamaServerOptions, done);
+    server.start();
+});
+
 gulp.task("tests-whatsnew", function (done) {
     // Only checks on Travis
     if (!process.env.TRAVIS) {

+ 127 - 0
Viewer/tests/Lib/PixelPixie.ts

@@ -0,0 +1,127 @@
+import { Helper } from "../commons/helper";
+import { AbstractViewer } from "babylonjs-viewer";
+
+
+export class PixelPixieUtils {
+    public static threshold = 3;
+    public static errorRatio = 1;
+
+    public static loadReferenceImage(name: string, callback: (success) => void) {
+        const img = Helper.getReferenceImg();
+        const timeout = setTimeout(() => {
+            img.onload = null;
+
+            if (callback) {
+                callback(false);
+            }
+        }, 1000);
+        img.onload = () => {
+            clearTimeout(timeout);
+            const resultCanvas = Helper.getReferenceCanvas();
+            const resultContext = resultCanvas.getContext("2d");
+            resultCanvas.width = img.width;
+            resultCanvas.height = img.height;
+            resultContext.drawImage(img, 0, 0);
+
+            if (callback) {
+                callback(true);
+            }
+        };
+
+        img.src = "base/assets/referenceImages/" + name + ".png";
+    }
+
+    public static compare(canvas: HTMLCanvasElement, renderData: Uint8Array, stats: { maxDelta: number, differencesCount: number }): boolean {
+        const referenceCanvas = canvas;
+        const width = referenceCanvas.width;
+        const height = referenceCanvas.height;
+        const size = width * height * 4;
+
+        const referenceContext = referenceCanvas.getContext("2d");
+
+        const referenceData = referenceContext.getImageData(0, 0, width, height);
+
+        let maxDelta = 0;
+        let differencesCount = 0;
+        for (let index = 0; index < size; index += 4) {
+            const [r, g, b] = [index, index + 1, index + 2];
+
+            const maxComponentDelta = Math.max(
+                Math.abs(renderData[r] - referenceData.data[r]),
+                Math.abs(renderData[g] - referenceData.data[g]),
+                Math.abs(renderData[b] - referenceData.data[b])
+            );
+
+            maxDelta = Math.max(maxDelta, maxComponentDelta);
+
+            if (maxComponentDelta < this.threshold) {
+                continue;
+            }
+
+            referenceData.data[r] = 255;
+            referenceData.data[g] *= 0.5;
+            referenceData.data[b] *= 0.5;
+            differencesCount++;
+        }
+
+        referenceContext.putImageData(referenceData, 0, 0);
+
+        stats.maxDelta = maxDelta;
+        stats.differencesCount = differencesCount;
+
+        return (differencesCount * 100) / (width * height) > this.errorRatio;
+    }
+
+    public static getRenderData(renderEngine: AbstractViewer): Uint8Array {
+        const width = renderEngine.canvas.width;
+        const height = renderEngine.canvas.height;
+
+        const renderData = renderEngine.engine.readPixels(0, 0, width, height);
+        const numberOfChannelsByLine = width * 4;
+        const halfHeight = height / 2;
+
+        for (let i = 0; i < halfHeight; i++) {
+            for (let j = 0; j < numberOfChannelsByLine; j++) {
+                const currentCell = j + i * numberOfChannelsByLine;
+                const targetLine = height - i - 1;
+                const targetCell = j + targetLine * numberOfChannelsByLine;
+
+                const temp = renderData[currentCell];
+                renderData[currentCell] = renderData[targetCell];
+                renderData[targetCell] = temp;
+            }
+        }
+
+        return renderData;
+    }
+
+    public static evaluate(testName, renderEngine: AbstractViewer, callback: (result: boolean, picture: string, maxDelta: number, differencesCount: number) => void): void {
+        renderEngine.scene.executeWhenReady(() => {
+            // Extra render shouldn't be necessary, this is due to a bug in IE
+
+            //TODO - this should be the viewer's render loop
+            renderEngine.forceRender();
+
+            const renderData = this.getRenderData(renderEngine);
+            Helper.getRenderImg().src = renderEngine.canvas.toDataURL();
+
+            renderEngine.runRenderLoop = false;
+
+            this.loadReferenceImage(testName, (success) => {
+                const referenceCanvas = Helper.getReferenceCanvas();
+                if (success) {
+                    const stats = { maxDelta: 0, differencesCount: 0 };
+                    const different = this.compare(referenceCanvas, renderData, stats);
+                    const resultPicture = referenceCanvas.toDataURL();
+                    Helper.getReferenceImg().onload = null;
+                    Helper.getReferenceImg().src = resultPicture;
+
+                    callback(!different, resultPicture, stats.maxDelta, stats.differencesCount);
+                }
+                else {
+                    callback(false, "Reference image not loaded.", 0, 0);
+                }
+            });
+        });
+    }
+}

+ 89 - 0
Viewer/tests/commons/boot.ts

@@ -0,0 +1,89 @@
+// import webglSupport from './mockWebGL';
+import { viewerGlobals } from 'babylonjs-viewer';
+import { Helper } from "./helper";
+
+export class Boot {
+    public static AppendResult = false;
+
+    public static main() {
+        console.log("main")
+        //let babylonSource = Boot.loadSync('base/js/babylon.viewer.max.js');
+        //let spectreSource = Boot.loadSync('base/js/spectreonly.js');
+
+        document.body.innerHTML = `<div id="result-div"></div><div id="working-div"></div>`;
+
+        //register actions to occur before each test
+        beforeEach(function (done) {
+            // tslint:disable-next-line:no-console
+            //console.debug('> Executing "' + details.name + '"');
+
+            //clear DOM and create canvas and container
+            document.getElementById('working-div').innerHTML = `<div style="font-size:30px;">WORKING CANVASES.</div> 
+				<div id="viewer-testing" style="width:512px;height:512px;">
+					<div id="renderCanvas" width="512" height="512" style="width:512px;height:512px;"></div>
+					<canvas id="referenceCanvas" width="512" height="512" style="width:512px;height:512px;"></canvas>
+				</div>
+			`;
+
+            if (Boot.AppendResult) {
+                var newResult = document.createElement('div');
+                document.getElementById('result-div').appendChild(newResult);
+
+                newResult.innerHTML = `<div class="result">
+						<div class="resultDisplay"></div>
+						<img class="renderImg" width="512" height="512" style="width:512px;height:512px;"></img>
+						<img class="referenceImg" width="512" height="512" style="width:512px;height:512px;"></img>
+                    </div>`;
+
+                /*if (!(<any>window).BABYLON) {
+                    eval.call(null, babylonSource);
+                    eval.call(null, spectreSource);
+                }*/
+
+            }
+            else {
+                //reset global state before executing test
+                //delete (<any>window).BABYLON;
+                //delete (<any>window).BabylonViewer;
+                //delete (<any>window).SPECTRE;
+
+                /*eval.call(null, babylonSource);
+                eval.call(null, spectreSource);*/
+            }
+
+            viewerGlobals.disableInit = true;
+
+            var DOMContentLoaded_event = document.createEvent("Event")
+            DOMContentLoaded_event.initEvent("DOMContentLoaded", true, true)
+            window.document.dispatchEvent(DOMContentLoaded_event);
+
+            // Disable Webgl2 support in test mode for Phantom/IE compatibility.
+            viewerGlobals.disableWebGL2Support = true;
+            done();
+        });
+
+        afterEach(function (done) {
+            Helper.disposeViewer();
+            //(<any>window).BabylonViewer.disposeAll();
+            done();
+        });
+    }
+
+    /*private static loadSync(url: string): string {
+        var req = new XMLHttpRequest();
+        req.open('GET', url, false);
+        req.send();
+        if (req.status >= 200 && req.status < 300) {
+            //successful request
+            return req.responseText;
+        } else {
+            //failed request
+            console.error(req.status + ' ' + req.statusText);
+            return null;
+        }
+    }*/
+
+}
+
+// webglSupport();
+export var main = Boot.main;

文件差異過大導致無法顯示
+ 168 - 0
Viewer/tests/commons/helper.ts


+ 16 - 0
Viewer/tests/package.json

@@ -0,0 +1,16 @@
+{
+    "name": "babylonjsviewerunittest",
+    "version": "7.7.7",
+    "description": "Unit Tests Suite For Babylon.js' viewer",
+    "main": "",
+    "repository": {
+        "url": "https://github.com/BabylonJS/Babylon.js/"
+    },
+    "readme": "https://github.com/BabylonJS/Babylon.js/edit/master/readme.md",
+    "license": "(Apache-2.0)",
+    "devDependencies": {
+        "@types/mocha": "2.2.46",
+        "@types/chai": "^4.1.0",
+        "@types/sinon": "^4.1.3"
+    }
+}

+ 406 - 0
Viewer/tests/unit/src/Viewer/viewer.ts

@@ -0,0 +1,406 @@
+import { AbstractViewer } from "babylonjs-viewer";
+import { Helper, NullEngineDefaultViewer } from "../../../commons/helper";
+import { assert, expect } from "../../viewerReference";
+
+/**
+ * To prevent test-state-leakage ensure that there is a viewer.dispose() for every new DefaultViewer
+ */
+
+describe('Viewer', function () {
+    it('should initialize a new viewer', (done) => {
+        let viewer = new NullEngineDefaultViewer(Helper.getViewerContainer());
+        viewer.onInitDoneObservable.add(() => {
+            assert.isTrue(viewer != undefined, "Viewer can not be instantiated.");
+            viewer.dispose();
+            done();
+        });
+    });
+
+    it('should not initialize if canvas is undefined', (done) => {
+        let viewer: AbstractViewer;
+        try {
+            viewer = new NullEngineDefaultViewer(undefined);
+            expect(viewer).not.to.exist;
+            if (viewer) viewer.dispose();
+        } catch (e) {
+            // exception was thrown, we are happy
+            assert.isTrue(true);
+        }
+        done();
+
+    });
+});
+
+export default (function () {
+    /*describe('Viewer', function () {
+        it('should initialize a new viewer', () => {
+            let viewer = new DefaultViewer(Helper.getCanvas());
+            assert.isTrue(viewer != undefined, "Viewer can not be instantiated.");
+            viewer.dispose();
+        });
+
+        it('should not initialize if canvas is undefined', () => {
+            let viewer: AbstractViewer;
+            try {
+                viewer = new DefaultViewer(undefined);
+                expect(viewer).not.to.exist;
+            } catch (e) {
+                // exception was thrown, we are happy
+                assert.isTrue(true);
+            }
+
+            if (viewer) viewer.dispose();
+        });
+    })*/
+})();
+//}
+
+
+
+/*QUnit.test('Viewer HDR', function (assert) {
+    let done = assert.async();
+
+    //override _handleHardwareLimitations with no-op to ensure HDR isn't disabled
+    (<any>AbstractViewer.prototype)._handleHardwareLimitations = () => { };
+
+    let viewer: AbstractViewer;
+
+    let frameCount = 0;
+    viewer = new DefaultViewer(Helper.getCanvas(), {
+        hdr: true,
+        renderCallback: () => {
+            frameCount++;
+            if (frameCount === 30) {
+                viewer.dispose();
+                viewer = null;
+                assert.ok(true, 'Successfully rendered 30 HDR frames and disposed');
+                done();
+            }
+        }
+    });
+    viewer.onInitDoneObservable.add(() => {
+        assert.ok(true, "not initialized");
+    });
+});
+
+QUnit.test('Viewer LDR', function (assert) {
+    let done = assert.async();
+
+    let viewer: AbstractViewer;
+
+    let frameCount = 0;
+    viewer = new DefaultViewer(Helper.getCanvas(), {
+        hdr: false,
+        renderCallback: () => {
+            frameCount++;
+            if (frameCount === 30) {
+                viewer.dispose();
+                viewer = null;
+                assert.ok(true, 'Successfully rendered 30 LDR frames and disposed');
+                done();
+            }
+        }
+    });
+});
+
+
+QUnit.test('Viewer hide show', function (assert) {
+    assert.expect(2);
+    let viewer = new DefaultViewer(Helper.getCanvas());
+
+    viewer.hide();
+
+    QUnit.assert.ok(Helper.getCanvas().style.display == "none", "Viewer can be hidden.");
+
+    viewer.show();
+
+    QUnit.assert.ok(Helper.getCanvas().style.display != "none", "Viewer can be shown after hiding.");
+
+    viewer.dispose();
+});
+
+QUnit.test('Viewer disable rendering', function (assert) {
+    let done = assert.async();
+    let renderCount = 0;
+
+    let viewer = new DefaultViewer(Helper.getCanvas(), {
+        renderCallback: function () {
+            renderCount++;
+        }
+    });
+
+    window.requestAnimationFrame(function () {
+        QUnit.assert.strictEqual(renderCount, 1, "Viewer renders by default.");
+
+        viewer.DisableRender = true;
+
+        QUnit.assert.ok(viewer.DisableRender === true, "DisableRender can be set");
+
+        window.requestAnimationFrame(function () {
+
+            QUnit.assert.strictEqual(renderCount, 1, "Viewer does not render with DisableRender set to true");
+
+            viewer.DisableRender = false;
+
+            window.requestAnimationFrame(function () {
+                QUnit.assert.strictEqual(renderCount, 2, "Viewer renders again when DisableRender is set to false");
+
+                viewer.dispose();
+                done();
+            });
+
+        });
+
+    });
+
+});
+
+QUnit.test('Viewer disable render in background', function (assert) {
+    let viewer = new DefaultViewer(Helper.getCanvas());
+
+    QUnit.assert.ok(viewer.RenderInBackground, "Viewer renders in background default.");
+
+    viewer.dispose();
+    viewer = null;
+
+    viewer = new DefaultViewer(Helper.getCanvas(), {
+        disableRenderInBackground: true
+    });
+
+    QUnit.assert.ok(viewer.RenderInBackground === false, "Viewer does not render in background with disableRenderInBackground set to true.");
+
+    viewer.dispose();
+});
+
+QUnit.test('Viewer disable camera control', function (assert) {
+    let viewer = new DefaultViewer(Helper.getCanvas());
+
+    QUnit.assert.ok(viewer.Scene.Camera.inputs.attachedElement, "Viewer should attach camera control by default.");
+
+    viewer.dispose();
+    viewer = null;
+
+    viewer = new DefaultViewer(Helper.getCanvas(), {
+        disableCameraControl: true
+    });
+
+    QUnit.assert.ok(!viewer.Scene.Camera.inputs.attachedElement, "Viewer should not attach camera control with disableCameraControl set to true.");
+
+    viewer.dispose();
+});
+
+QUnit.test('Viewer disable ctrl for panning', function (assert) {
+    let viewer = new DefaultViewer(Helper.getCanvas());
+
+    QUnit.assert.ok(viewer.Scene.Camera._useCtrlForPanning, "Viewer should use CTRL for panning by default.");
+
+    viewer.dispose();
+    viewer = null;
+
+    viewer = new DefaultViewer(Helper.getCanvas(), {
+        disableCtrlForPanning: true
+    });
+
+    QUnit.assert.ok(viewer.Scene.Camera._useCtrlForPanning === false, "Viewer should not use CTRL for panning with disableCameraControl set to true.");
+    viewer.dispose();
+});
+
+QUnit.test('Viewer return build number', function (assert) {
+    let viewer = new DefaultViewer(Helper.getCanvas());
+
+    QUnit.assert.ok(AbstractViewer.BuildNumber, "Viewer should return a Build Number.");
+
+    viewer.dispose();
+});
+
+QUnit.test('Viewer resize', function (assert) {
+    let canvas = Helper.getCanvas();
+    let viewer = new DefaultViewer(canvas);
+
+    let resizeCount = 0;
+
+    BABYLON.Engine.prototype.resize = function () {
+        resizeCount++;
+    };
+
+    // any since it is protected
+    (<any>viewer)._resize();
+
+    QUnit.assert.equal(resizeCount, 1, "Engine should resize when Viewer.resize() is called.");
+
+    canvas.style.width = '0px';
+    canvas.style.height = '0px';
+
+    // any since it is protected
+    (<any>viewer)._resize();
+
+    QUnit.assert.equal(resizeCount, 1, "Engine should not resize when the canvas has width/height 0.");
+
+    viewer.dispose();
+    // any since it is protected
+    (<any>viewer)._resize();
+
+    QUnit.assert.equal(resizeCount, 1, "Engine should not resize when if Viewer has been disposed.");
+
+});
+
+QUnit.test('Viewer get models', function (assert) {
+    let viewer = new DefaultViewer(Helper.getCanvas());
+
+    let mesh1 = Helper.createMockMesh(viewer);
+    let mesh2 = Helper.createMockMesh(viewer);
+    let model1 = new SPECTRE.Model(viewer, "Model 1");
+    let model2 = new SPECTRE.Model(viewer, "Model 2");
+    model1.setMesh(mesh1);
+    model2.setMesh(mesh2);
+
+    viewer.Scene.addModel(model1, false);
+    viewer.Scene.addModel(model2, false);
+
+    QUnit.assert.equal(viewer.Scene.Models.length, 2, "Viewer.getModels should return all models in the scene by default.");
+
+    // Further tests fail unless this viewer is disposed
+    // TODO fully isolate tests
+    viewer.dispose();
+});
+
+QUnit.test('Viewer model add/remove', function (assert) {
+    let modelsInScene = 0;
+
+    let viewer = new DefaultViewer(Helper.getCanvas(), {
+        onModelAdd: function () {
+            modelsInScene += 1;
+        },
+        onModelRemove: function () {
+            modelsInScene -= 1;
+        }
+    });
+
+    let mesh1 = Helper.createMockMesh(viewer);
+    let model = new SPECTRE.Model(viewer, "Model");
+    model.setMesh(mesh1);
+
+    viewer.Scene.addModel(model, false);
+
+    QUnit.assert.equal(modelsInScene, 1, "onModelAdd should be called when a model is registered");
+
+    viewer.Scene.removeModel(model, false);
+
+    QUnit.assert.equal(modelsInScene, 0, "onModelRemove should be called when a model is unregistered");
+
+    viewer.dispose();
+});
+
+QUnit.test('Viewer typical case with dispose', function (assert) {
+    let done = assert.async();
+
+    let viewer = new DefaultViewer(Helper.getCanvas(), {
+        environmentAssetsRootURL: 'base/assets/environment/',
+        environmentMap: 'legacy/joa-256.env',
+        unifiedConfiguration: 'base/assets/UnifiedConfiguration.json'
+    });
+
+    //load different models sequentially to simulate typical use
+    viewer.loadGLTF('base/assets/Modok/Modok.FBX.gltf', {
+        completeCallback: (model) => {
+            model.EngineModel.translate(new BABYLON.Vector3(1, 0, 0), 0.1);
+
+            setTimeout(() => {
+                viewer.Scene.removeModel(model, true, () => {
+                    viewer.loadGLTF('base/assets/Modok/Modok.FBX.gltf', {
+                        readyCallback: () => {
+                            //starting loading a few assets and ensure there's no failure when disposing
+                            viewer.loadEnvironment('legacy/joa-256.env', () => {
+                                assert.ok(false, 'Viewer should have been disposed! Load should not complete.');
+                            });
+                            viewer.loadGLTF('base/assets/Modok/Modok.FBX.gltf', {
+                                readyCallback: () => {
+                                    assert.ok(false, 'Viewer should have been disposed! Load should not complete.');
+                                },
+                            });
+
+                            try {
+                                console.log('Disposing viewer');
+                                viewer.dispose();
+                                viewer = null;
+                                console.log('Viewer disposed');
+                            } catch (e) {
+                                assert.ok(false, `Viewer failed to dispose without exception ${e}`);
+                            }
+
+                            setTimeout(() => {
+                                //wait some time to verify there were no exceptions no complete callbacks fire unexpectedly
+                                assert.strictEqual(viewer, null, 'Viewer should be set to null');
+                                done();
+                            }, 2000);
+                        }
+                    });
+                });
+            }, 3000);
+        }
+    });
+});
+
+QUnit.test('Test getEnvironmentAssetUrl relative no root', function (assert) {
+    var viewer = Helper.createViewer();
+    assert.ok(viewer.getEnvironmentAssetUrl("foo.png") === "foo.png", "Relative url should be return unmodified without configuration.");
+});
+
+QUnit.test('Test getEnvironmentAssetUrl absolute no root', function (assert) {
+    var viewer = Helper.createViewer();
+    assert.ok(viewer.getEnvironmentAssetUrl("http://foo.png") === "http://foo.png", "Absolute url should not be undefined without configuration.");
+});
+
+QUnit.test('Test getEnvironmentAssetUrl relative root', function (assert) {
+    var viewer = Helper.createViewer({ environmentAssetsRootURL: "https://foo/" });
+    assert.ok(viewer.getEnvironmentAssetUrl("foo.png") === "https://foo/foo.png", "Relative url should not be be undefined with configuration.");
+});
+
+QUnit.test('Test getEnvironmentAssetUrl absolute root', function (assert) {
+    var viewer = Helper.createViewer({ environmentAssetsRootURL: "https://foo/" });
+    assert.ok(viewer.getEnvironmentAssetUrl("http://foo.png") === "http://foo.png", "Absolute url should not be undefined with configuration.");
+});
+
+QUnit.test('unlockBabylonFeatures', function () {
+    let viewer = Helper.createViewer();
+
+    QUnit.assert.ok(viewer.Scene.EngineScene.shadowsEnabled, "shadowsEnabled");
+    QUnit.assert.ok(!viewer.Scene.EngineScene.particlesEnabled, "particlesEnabled");
+    QUnit.assert.ok(!viewer.Scene.EngineScene.collisionsEnabled, "collisionsEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.lightsEnabled, "lightsEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.texturesEnabled, "texturesEnabled");
+    QUnit.assert.ok(!viewer.Scene.EngineScene.lensFlaresEnabled, "lensFlaresEnabled");
+    QUnit.assert.ok(!viewer.Scene.EngineScene.proceduralTexturesEnabled, "proceduralTexturesEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.renderTargetsEnabled, "renderTargetsEnabled");
+    QUnit.assert.ok(!viewer.Scene.EngineScene.spritesEnabled, "spritesEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.skeletonsEnabled, "skeletonsEnabled");
+    QUnit.assert.ok(!viewer.Scene.EngineScene.audioEnabled, "audioEnabled");
+
+    viewer.unlockBabylonFeatures();
+
+    QUnit.assert.ok(viewer.Scene.EngineScene.shadowsEnabled, "shadowsEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.particlesEnabled, "particlesEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.postProcessesEnabled, "postProcessesEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.collisionsEnabled, "collisionsEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.lightsEnabled, "lightsEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.texturesEnabled, "texturesEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.lensFlaresEnabled, "lensFlaresEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.proceduralTexturesEnabled, "proceduralTexturesEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.renderTargetsEnabled, "renderTargetsEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.spritesEnabled, "spritesEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.skeletonsEnabled, "skeletonsEnabled");
+    QUnit.assert.ok(viewer.Scene.EngineScene.audioEnabled, "audioEnabled");
+});
+
+QUnit.test('Take Screenshot', function (assert) {
+    let viewer = Helper.createViewer();
+    let done = assert.async();
+
+    Helper.MockScreenCapture(viewer, Helper.mockScreenCaptureData());
+
+    viewer.takeScreenshot(function (data) {
+        QUnit.assert.ok(data === Helper.mockScreenCaptureData(), "Screenshot failed.");
+        done();
+    });
+});
+*/

+ 3 - 0
Viewer/tests/unit/src/index.ts

@@ -0,0 +1,3 @@
+import { main } from '../../commons/boot';
+main();
+export * from './Viewer/viewer';

+ 8 - 0
Viewer/tests/unit/src/viewerReference.ts

@@ -0,0 +1,8 @@
+/// <reference path="../../../../dist/preview release/viewer/babylon.viewer.module.d.ts" />
+
+/*
+ * Create a constant with the ChaiJS' expect module just to make the code more readable.
+ */
+export const should = chai.should();
+export const expect = chai.expect;
+export const assert = chai.assert;

+ 24 - 0
Viewer/tests/unit/tsconfig.json

@@ -0,0 +1,24 @@
+{
+    "compilerOptions": {
+        "target": "es5",
+        "module": "commonjs",
+        "noUnusedLocals": true,
+        "noUnusedParameters": false,
+        "forceConsistentCasingInFileNames": true,
+        "noResolve": false,
+        "experimentalDecorators": true,
+        "declaration": false,
+        "noImplicitAny": false,
+        "noEmitOnError": false,
+        "removeComments": false,
+        "sourceMap": true,
+        "lib": [
+            "dom",
+            "es2015.promise",
+            "es5"
+        ],
+    },
+    "include": [
+        "./src/**/*.ts"
+    ]
+}

+ 12 - 0
Viewer/tests/unit/viewerReference.ts

@@ -0,0 +1,12 @@
+/// <reference path="../../../dist/preview release/viewer/babylon.viewer.module.d.ts" />
+
+/// <reference path="../node_modules/@types/chai/index.d.ts" />
+/// <reference path="../node_modules/@types/mocha/index.d.ts" />
+/// <reference path="../node_modules/@types/sinon/index.d.ts" />
+
+/*
+ * Create a constant with the ChaiJS' expect module just to make the code more readable.
+ */
+export const should = chai.should();
+export const expect = chai.expect;
+export const assert = chai.assert;

+ 2 - 1
Viewer/tsconfig-gulp.json

@@ -31,6 +31,7 @@
     },
     "exclude": [
         "node_modules",
-        "dist"
+        "dist",
+        "tests"
     ]
 }