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