viewer.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. import { Helper } from "../../../commons/helper";
  2. import { assert, expect, should } from "../viewerReference";
  3. import { DefaultViewer, AbstractViewer, Version, viewerManager } from "../../../../src";
  4. import { Engine } from "babylonjs";
  5. export let name = "viewer Tests";
  6. /**
  7. * To prevent test-state-leakage ensure that there is a viewer.dispose() for every new DefaultViewer
  8. */
  9. describe('Viewer', function() {
  10. it('should initialize a new viewer and its internal variables', (done) => {
  11. let viewer = Helper.getNewViewerInstance();
  12. assert.isDefined(viewer.baseId, "base id should be defined");
  13. assert.isDefined(viewer.modelLoader, "model loader should be defined");
  14. viewer.onInitDoneObservable.add(() => {
  15. assert.isDefined(viewer, "Viewer can not be instantiated.");
  16. assert.isDefined(viewer.sceneManager, "scene manager should be defined");
  17. viewer.dispose();
  18. done();
  19. });
  20. });
  21. it('should be added to the viewer manager', (done) => {
  22. let viewer = Helper.getNewViewerInstance();
  23. viewer.onInitDoneObservable.add(() => {
  24. assert.isDefined(viewerManager.getViewerById(viewer.baseId), "Viewer was not added to the viewer manager.");
  25. viewer.dispose();
  26. done();
  27. });
  28. });
  29. it('should have a defined canvas', (done) => {
  30. let viewer = Helper.getNewViewerInstance();
  31. viewer.onInitDoneObservable.add(() => {
  32. assert.isDefined(viewer.canvas, "Canvas is not defined");
  33. assert.isTrue(viewer.canvas instanceof HTMLCanvasElement, "Canvas is not a canvas");
  34. viewer.dispose();
  35. done();
  36. });
  37. });
  38. it('should not initialize if element is undefined', (done) => {
  39. try {
  40. // force typescript to "think" that the element exist with "!"
  41. let viewer = Helper.getNewViewerInstance(document.getElementById('doesntexist')!);
  42. expect(viewer).not.to.exist;
  43. if (viewer) { viewer.dispose(); }
  44. } catch (e) {
  45. // exception was thrown, we are happy
  46. assert.isTrue(true);
  47. }
  48. done();
  49. });
  50. it('should be shown and hidden', (done) => {
  51. let viewer: DefaultViewer = <DefaultViewer>Helper.getNewViewerInstance();
  52. viewer.onInitDoneObservable.add(() => {
  53. // default visibility is not none
  54. const htmlElement = viewer.containerElement as HTMLElement;
  55. expect(htmlElement.style.display).not.to.equal('none');
  56. viewer.hide().then(() => {
  57. // element is hidden
  58. assert.equal(htmlElement.style.display, 'none', "Viewer is still visible");
  59. viewer.show().then(() => {
  60. //element is shown
  61. assert.notEqual(htmlElement.style.display, 'none', "Viewer is not visible");
  62. viewer.dispose();
  63. done();
  64. });
  65. });
  66. });
  67. });
  68. it('should execute registered functions on every rendered frame', (done) => {
  69. let viewer: DefaultViewer = <DefaultViewer>Helper.getNewViewerInstance();
  70. let renderCount = 0;
  71. let sceneRenderCount = 0;
  72. viewer.onSceneInitObservable.add((scene) => {
  73. viewer.sceneManager.scene.registerBeforeRender(() => {
  74. sceneRenderCount++;
  75. });
  76. viewer.onFrameRenderedObservable.add(() => {
  77. renderCount++;
  78. assert.equal(renderCount, sceneRenderCount, "function was not executed with each frame");
  79. if (renderCount === 20) {
  80. viewer.dispose();
  81. done();
  82. }
  83. });
  84. });
  85. });
  86. it('should disable and enable rendering', (done) => {
  87. let viewer: DefaultViewer = <DefaultViewer>Helper.getNewViewerInstance();
  88. let renderCount = 0;
  89. viewer.onInitDoneObservable.add(() => {
  90. viewer.onFrameRenderedObservable.add(() => {
  91. renderCount++;
  92. });
  93. assert.equal(renderCount, 0);
  94. window.requestAnimationFrame(function() {
  95. assert.equal(renderCount, 1, "render loop should have been executed");
  96. viewer.runRenderLoop = false;
  97. window.requestAnimationFrame(function() {
  98. assert.equal(renderCount, 1, "Render loop should not have been executed");
  99. viewer.runRenderLoop = true;
  100. window.requestAnimationFrame(function() {
  101. assert.equal(renderCount, 2, "render loop should have been executed again");
  102. viewer.dispose();
  103. done();
  104. });
  105. });
  106. });
  107. });
  108. });
  109. it('should have a version', (done) => {
  110. assert.exists(Version, "Viewer should have a version");
  111. assert.equal(Version, Engine.Version, "Viewer version should equal to Babylon's engine version");
  112. done();
  113. });
  114. it('should resize the viewer correctly', (done) => {
  115. let viewer: DefaultViewer = <DefaultViewer>Helper.getNewViewerInstance();
  116. let resizeCount = 0;
  117. //wait for the engine to init
  118. viewer.onEngineInitObservable.add((engine) => {
  119. // mock the resize function
  120. engine.resize = () => {
  121. resizeCount++;
  122. };
  123. });
  124. viewer.onInitDoneObservable.add(() => {
  125. assert.equal(resizeCount, 0);
  126. viewer.forceResize();
  127. assert.equal(resizeCount, 1, "Engine should resize when Viewer.forceResize() is called.");
  128. viewer.updateConfiguration({
  129. engine: {
  130. disableResize: true
  131. }
  132. });
  133. viewer.forceResize();
  134. assert.equal(resizeCount, 1, "Engine should not resize when disableResize is enabled");
  135. viewer.updateConfiguration({
  136. engine: {
  137. disableResize: false
  138. }
  139. });
  140. viewer.canvas.style.width = '0px';
  141. viewer.canvas.style.height = '0px';
  142. viewer.forceResize();
  143. assert.equal(resizeCount, 1, "Engine should not resize when the canvas has width/height 0.");
  144. viewer.dispose();
  145. // any since it is protected
  146. viewer.forceResize();
  147. assert.equal(resizeCount, 1, "Engine should not resize when if Viewer has been disposed.");
  148. done();
  149. });
  150. });
  151. it('should render in background if set to true', (done) => {
  152. let viewer = Helper.getNewViewerInstance();
  153. viewer.onInitDoneObservable.add(() => {
  154. assert.isTrue(viewer.engine.renderEvenInBackground, "Engine is rendering in background");
  155. assert.equal(viewer.engine.renderEvenInBackground, viewer.renderInBackground, "engine render in background should be equal to the viewer's");
  156. viewer.updateConfiguration({
  157. scene: {
  158. renderInBackground: false
  159. }
  160. });
  161. assert.isFalse(viewer.engine.renderEvenInBackground, "Engine is not rendering in background");
  162. assert.equal(viewer.engine.renderEvenInBackground, viewer.renderInBackground, "engine render in background should be equal to the viewer's");
  163. viewer.dispose();
  164. done();
  165. });
  166. });
  167. it('should attach and detach camera control correctly', (done) => {
  168. let viewer = Helper.getNewViewerInstance();
  169. viewer.onInitDoneObservable.add(() => {
  170. assert.isDefined(viewer.sceneManager.camera.inputs.attachedElement, "Camera is not attached per default");
  171. viewer.updateConfiguration({
  172. scene: {
  173. disableCameraControl: true
  174. }
  175. });
  176. assert.isNull(viewer.sceneManager.camera.inputs.attachedElement, "Camera is still attached");
  177. viewer.updateConfiguration({
  178. scene: {
  179. disableCameraControl: false
  180. }
  181. });
  182. assert.isDefined(viewer.sceneManager.camera.inputs.attachedElement, "Camera not attached");
  183. viewer.dispose();
  184. done();
  185. });
  186. });
  187. it('should take screenshot when called', (done) => {
  188. let viewer = Helper.getNewViewerInstance();
  189. viewer.onInitDoneObservable.add(() => {
  190. Helper.MockScreenCapture(viewer, Helper.mockScreenCaptureData());
  191. viewer.takeScreenshot(function(data) {
  192. assert.equal(data, Helper.mockScreenCaptureData(), "Screenshot failed.");
  193. viewer.dispose();
  194. done();
  195. });
  196. });
  197. });
  198. it('should notify observers correctly during init', (done) => {
  199. let viewer = Helper.getNewViewerInstance();
  200. let shouldBeRendering = false;
  201. viewer.onFrameRenderedObservable.add(() => {
  202. assert.isTrue(shouldBeRendering, "rendered before init done");
  203. viewer.dispose();
  204. done();
  205. });
  206. viewer.onEngineInitObservable.add((engine) => {
  207. assert.equal(engine, viewer.engine, "engine instance is not the same");
  208. assert.isUndefined(viewer.sceneManager.scene, "scene exists before initScene");
  209. });
  210. viewer.onSceneInitObservable.add((scene) => {
  211. assert.equal(scene, viewer.sceneManager.scene, "scene instance is not the same");
  212. });
  213. viewer.onInitDoneObservable.add((viewerInstance) => {
  214. assert.isDefined(viewerInstance.sceneManager.scene, "scene is not defined");
  215. //scene exists, it should now start rendering
  216. shouldBeRendering = true;
  217. });
  218. });
  219. it('should render if forceRender was called', (done) => {
  220. let viewer = Helper.getNewViewerInstance();
  221. viewer.runRenderLoop = false;
  222. viewer.onInitDoneObservable.add(() => {
  223. viewer.onFrameRenderedObservable.add(() => {
  224. assert.isTrue(true, "not rendered");
  225. viewer.dispose();
  226. done();
  227. });
  228. viewer.forceRender();
  229. });
  230. });
  231. it('should have the correct base ID', (done) => {
  232. let element = document.createElement("div");
  233. let randomString = "" + Math.random();
  234. element.id = randomString;
  235. let viewer = Helper.getNewViewerInstance(element);
  236. assert.equal(viewer.baseId, viewer.containerElement.id);
  237. assert.equal(randomString, viewer.baseId);
  238. viewer.dispose();
  239. done();
  240. });
  241. it('should update the configuration object when updateConfiguration is called', (done) => {
  242. let randomVersion = "" + Math.random();
  243. let viewer = Helper.getNewViewerInstance(undefined, {
  244. version: randomVersion
  245. });
  246. viewer.onInitDoneObservable.add(() => {
  247. assert.equal(viewer.configuration.version, randomVersion);
  248. let newRandom = "" + Math.random();
  249. viewer.updateConfiguration({
  250. version: newRandom
  251. });
  252. assert.equal(viewer.configuration.version, newRandom);
  253. viewer.dispose();
  254. done();
  255. });
  256. });
  257. it('should not init engine if viewer is disposed right after created', (done) => {
  258. let viewer = Helper.getNewViewerInstance();
  259. viewer.dispose();
  260. // wait a bit for the engine to initialize, if failed
  261. let timeout = setTimeout(() => {
  262. assert.isUndefined(viewer.engine);
  263. done();
  264. }, 1000);
  265. viewer.onEngineInitObservable.add(() => {
  266. assert.fail();
  267. clearTimeout(timeout);
  268. done();
  269. });
  270. });
  271. });
  272. //}
  273. /*
  274. QUnit.test('Viewer disable ctrl for panning', function (assert) {
  275. let viewer = new DefaultViewer(Helper.getCanvas());
  276. QUnit.assert.ok(viewer.Scene.Camera._useCtrlForPanning, "Viewer should use CTRL for panning by default.");
  277. viewer.dispose();
  278. viewer = null;
  279. viewer = new DefaultViewer(Helper.getCanvas(), {
  280. disableCtrlForPanning: true
  281. });
  282. QUnit.assert.ok(viewer.Scene.Camera._useCtrlForPanning === false, "Viewer should not use CTRL for panning with disableCameraControl set to true.");
  283. viewer.dispose();
  284. });
  285. QUnit.test('Viewer get models', function (assert) {
  286. let viewer = new DefaultViewer(Helper.getCanvas());
  287. let mesh1 = Helper.createMockMesh(viewer);
  288. let mesh2 = Helper.createMockMesh(viewer);
  289. let model1 = new SPECTRE.Model(viewer, "Model 1");
  290. let model2 = new SPECTRE.Model(viewer, "Model 2");
  291. model1.setMesh(mesh1);
  292. model2.setMesh(mesh2);
  293. viewer.Scene.addModel(model1, false);
  294. viewer.Scene.addModel(model2, false);
  295. QUnit.assert.equal(viewer.Scene.Models.length, 2, "Viewer.getModels should return all models in the scene by default.");
  296. // Further tests fail unless this viewer is disposed
  297. // TODO fully isolate tests
  298. viewer.dispose();
  299. });
  300. QUnit.test('Viewer model add/remove', function (assert) {
  301. let modelsInScene = 0;
  302. let viewer = new DefaultViewer(Helper.getCanvas(), {
  303. onModelAdd: function () {
  304. modelsInScene += 1;
  305. },
  306. onModelRemove: function () {
  307. modelsInScene -= 1;
  308. }
  309. });
  310. let mesh1 = Helper.createMockMesh(viewer);
  311. let model = new SPECTRE.Model(viewer, "Model");
  312. model.setMesh(mesh1);
  313. viewer.Scene.addModel(model, false);
  314. QUnit.assert.equal(modelsInScene, 1, "onModelAdd should be called when a model is registered");
  315. viewer.Scene.removeModel(model, false);
  316. QUnit.assert.equal(modelsInScene, 0, "onModelRemove should be called when a model is unregistered");
  317. viewer.dispose();
  318. });
  319. QUnit.test('Viewer typical case with dispose', function (assert) {
  320. let done = assert.async();
  321. let viewer = new DefaultViewer(Helper.getCanvas(), {
  322. environmentAssetsRootURL: 'base/assets/environment/',
  323. environmentMap: 'legacy/joa-256.env',
  324. unifiedConfiguration: 'base/assets/UnifiedConfiguration.json'
  325. });
  326. //load different models sequentially to simulate typical use
  327. viewer.loadGLTF('base/assets/Modok/Modok.FBX.gltf', {
  328. completeCallback: (model) => {
  329. model.EngineModel.translate(new BABYLON.Vector3(1, 0, 0), 0.1);
  330. setTimeout(() => {
  331. viewer.Scene.removeModel(model, true, () => {
  332. viewer.loadGLTF('base/assets/Modok/Modok.FBX.gltf', {
  333. readyCallback: () => {
  334. //starting loading a few assets and ensure there's no failure when disposing
  335. viewer.loadEnvironment('legacy/joa-256.env', () => {
  336. assert.ok(false, 'Viewer should have been disposed! Load should not complete.');
  337. });
  338. viewer.loadGLTF('base/assets/Modok/Modok.FBX.gltf', {
  339. readyCallback: () => {
  340. assert.ok(false, 'Viewer should have been disposed! Load should not complete.');
  341. },
  342. });
  343. try {
  344. console.log('Disposing viewer');
  345. viewer.dispose();
  346. viewer = null;
  347. console.log('Viewer disposed');
  348. } catch (e) {
  349. assert.ok(false, `Viewer failed to dispose without exception ${e}`);
  350. }
  351. setTimeout(() => {
  352. //wait some time to verify there were no exceptions no complete callbacks fire unexpectedly
  353. assert.strictEqual(viewer, null, 'Viewer should be set to null');
  354. done();
  355. }, 2000);
  356. }
  357. });
  358. });
  359. }, 3000);
  360. }
  361. });
  362. });
  363. QUnit.test('Test getEnvironmentAssetUrl relative no root', function (assert) {
  364. var viewer = Helper.createViewer();
  365. assert.ok(viewer.getEnvironmentAssetUrl("foo.png") === "foo.png", "Relative url should be return unmodified without configuration.");
  366. });
  367. QUnit.test('Test getEnvironmentAssetUrl absolute no root', function (assert) {
  368. var viewer = Helper.createViewer();
  369. assert.ok(viewer.getEnvironmentAssetUrl("http://foo.png") === "http://foo.png", "Absolute url should not be undefined without configuration.");
  370. });
  371. QUnit.test('Test getEnvironmentAssetUrl relative root', function (assert) {
  372. var viewer = Helper.createViewer({ environmentAssetsRootURL: "https://foo/" });
  373. assert.ok(viewer.getEnvironmentAssetUrl("foo.png") === "https://foo/foo.png", "Relative url should not be be undefined with configuration.");
  374. });
  375. QUnit.test('Test getEnvironmentAssetUrl absolute root', function (assert) {
  376. var viewer = Helper.createViewer({ environmentAssetsRootURL: "https://foo/" });
  377. assert.ok(viewer.getEnvironmentAssetUrl("http://foo.png") === "http://foo.png", "Absolute url should not be undefined with configuration.");
  378. });
  379. */