modeldb.spec.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import 'jest';
  4. import { JSONExt } from '@lumino/coreutils';
  5. import {
  6. ModelDB,
  7. ObservableString,
  8. ObservableValue,
  9. ObservableUndoableList,
  10. ObservableJSON
  11. } from '@jupyterlab/observables';
  12. describe('@jupyterlab/observables', () => {
  13. describe('ObservableValue', () => {
  14. describe('#constructor', () => {
  15. it('should accept no arguments', () => {
  16. const value = new ObservableValue();
  17. expect(value instanceof ObservableValue).toBe(true);
  18. expect(value.get()).toBeNull();
  19. });
  20. it('should accept an initial JSON value', () => {
  21. const value = new ObservableValue('value');
  22. expect(value instanceof ObservableValue).toBe(true);
  23. const value2 = new ObservableValue({ one: 'one', two: 2 });
  24. expect(value2 instanceof ObservableValue).toBe(true);
  25. });
  26. });
  27. describe('#type', () => {
  28. it('should return `Value`', () => {
  29. const value = new ObservableValue();
  30. expect(value.type).toBe('Value');
  31. });
  32. });
  33. describe('#isDisposed', () => {
  34. it('should test whether the value is disposed', () => {
  35. const value = new ObservableValue();
  36. expect(value.isDisposed).toBe(false);
  37. value.dispose();
  38. expect(value.isDisposed).toBe(true);
  39. });
  40. });
  41. describe('#changed', () => {
  42. it('should be emitted when the map changes state', () => {
  43. let called = false;
  44. const value = new ObservableValue();
  45. value.changed.connect(() => {
  46. called = true;
  47. });
  48. value.set('set');
  49. expect(called).toBe(true);
  50. });
  51. it('should have value changed args', () => {
  52. let called = false;
  53. const value = new ObservableValue();
  54. value.changed.connect((sender, args) => {
  55. expect(sender).toBe(value);
  56. expect(args.newValue).toBe('set');
  57. expect(args.oldValue).toBeNull();
  58. called = true;
  59. });
  60. value.set('set');
  61. expect(called).toBe(true);
  62. });
  63. });
  64. describe('#get', () => {
  65. it('should get the value of the object', () => {
  66. const value = new ObservableValue('value');
  67. expect(value.get()).toBe('value');
  68. const value2 = new ObservableValue({ one: 'one', two: 2 });
  69. expect(JSONExt.deepEqual(value2.get(), { one: 'one', two: 2 })).toBe(
  70. true
  71. );
  72. });
  73. });
  74. describe('#set', () => {
  75. it('should set the value of the object', () => {
  76. const value = new ObservableValue();
  77. value.set('value');
  78. expect(value.get()).toBe('value');
  79. });
  80. });
  81. });
  82. describe('ModelDB', () => {
  83. describe('#constructor()', () => {
  84. it('should accept no arguments', () => {
  85. const db = new ModelDB();
  86. expect(db instanceof ModelDB).toBe(true);
  87. });
  88. it('should accept a basePath', () => {
  89. const db = new ModelDB({ basePath: 'base' });
  90. expect(db instanceof ModelDB).toBe(true);
  91. });
  92. it('should accept a baseDB', () => {
  93. const base = new ModelDB();
  94. const db = new ModelDB({ baseDB: base });
  95. expect(db instanceof ModelDB).toBe(true);
  96. });
  97. });
  98. describe('#isDisposed', () => {
  99. it('should test whether it is disposed', () => {
  100. const db = new ModelDB();
  101. expect(db.isDisposed).toBe(false);
  102. db.dispose();
  103. expect(db.isDisposed).toBe(true);
  104. });
  105. });
  106. describe('#basePath', () => {
  107. it('should return an empty string for a model without a baseDB', () => {
  108. const db = new ModelDB();
  109. expect(db.basePath).toBe('');
  110. });
  111. it('should return the base path', () => {
  112. const db = new ModelDB({ basePath: 'base' });
  113. expect(db.basePath).toBe('base');
  114. });
  115. });
  116. describe('#isPrepopulated', () => {
  117. it('should return false for an in-memory database', () => {
  118. const db = new ModelDB();
  119. expect(db.isPrepopulated).toBe(false);
  120. });
  121. });
  122. describe('#isCollaborative', () => {
  123. it('should return false for an in-memory database', () => {
  124. const db = new ModelDB();
  125. expect(db.isCollaborative).toBe(false);
  126. });
  127. });
  128. describe('#connected', () => {
  129. it('should resolve immediately for an in-memory database', () => {
  130. const db = new ModelDB();
  131. return db.connected;
  132. });
  133. });
  134. describe('#get', () => {
  135. it('should get a value that exists at a path', () => {
  136. const db = new ModelDB();
  137. const value = db.createValue('value');
  138. const value2 = db.get('value');
  139. expect(value2).toBe(value);
  140. });
  141. it('should return undefined for a value that does not exist', () => {
  142. const db = new ModelDB();
  143. expect(db.get('value')).toBeUndefined();
  144. });
  145. });
  146. describe('#has', () => {
  147. it('should return true if a value exists at a path', () => {
  148. const db = new ModelDB();
  149. db.createValue('value');
  150. expect(db.has('value')).toBe(true);
  151. });
  152. it('should return false for a value that does not exist', () => {
  153. const db = new ModelDB();
  154. expect(db.has('value')).toBe(false);
  155. });
  156. });
  157. describe('#createString', () => {
  158. it('should create an ObservableString`', () => {
  159. const db = new ModelDB();
  160. const str = db.createString('str');
  161. expect(str instanceof ObservableString).toBe(true);
  162. });
  163. it('should be able to retrieve that string using `get`', () => {
  164. const db = new ModelDB();
  165. const str = db.createString('str');
  166. expect(db.get('str')).toBe(str);
  167. });
  168. });
  169. describe('#createList', () => {
  170. it('should create an ObservableUndoableList`', () => {
  171. const db = new ModelDB();
  172. const str = db.createList('vec');
  173. expect(str instanceof ObservableUndoableList).toBe(true);
  174. });
  175. it('should be able to retrieve that vector using `get`', () => {
  176. const db = new ModelDB();
  177. const vec = db.createList('vec');
  178. expect(db.get('vec')).toBe(vec);
  179. });
  180. });
  181. describe('#createMap', () => {
  182. it('should create an ObservableMap`', () => {
  183. const db = new ModelDB();
  184. const map = db.createMap('map');
  185. expect(map instanceof ObservableJSON).toBe(true);
  186. });
  187. it('should be able to retrieve that map using `get`', () => {
  188. const db = new ModelDB();
  189. const map = db.createMap('map');
  190. expect(db.get('map')).toBe(map);
  191. });
  192. });
  193. describe('#createValue', () => {
  194. it('should create an ObservableValue`', () => {
  195. const db = new ModelDB();
  196. const value = db.createValue('value');
  197. expect(value instanceof ObservableValue).toBe(true);
  198. });
  199. it('should be able to retrieve that value using `get`', () => {
  200. const db = new ModelDB();
  201. const value = db.createString('value');
  202. expect(db.get('value')).toBe(value);
  203. });
  204. });
  205. describe('#setValue', () => {
  206. it('should set a value at a path', () => {
  207. const db = new ModelDB();
  208. const value = db.createValue('value');
  209. db.setValue('value', 'set');
  210. expect(value.get()).toBe('set');
  211. });
  212. });
  213. describe('#getValue', () => {
  214. it('should get a value at a path', () => {
  215. const db = new ModelDB();
  216. const value = db.createValue('value');
  217. value.set('set');
  218. expect(db.getValue('value')).toBe('set');
  219. });
  220. });
  221. describe('#view', () => {
  222. it('should should return a ModelDB', () => {
  223. const db = new ModelDB();
  224. const view = db.view('');
  225. expect(view instanceof ModelDB).toBe(true);
  226. expect(view === db).toBe(false);
  227. });
  228. it('should set the baseDB path on the view', () => {
  229. const db = new ModelDB();
  230. const view = db.view('base');
  231. expect(view.basePath).toBe('base');
  232. });
  233. it('should return a view onto the base ModelDB', () => {
  234. const db = new ModelDB();
  235. const view = db.view('base');
  236. db.createString('base.str1');
  237. expect(db.get('base.str1')).toBe(view.get('str1'));
  238. view.createString('str2');
  239. expect(db.get('base.str2')).toBe(view.get('str2'));
  240. });
  241. it('should be stackable', () => {
  242. const db = new ModelDB();
  243. const view = db.view('one');
  244. const viewView = view.view('two');
  245. expect(view.basePath).toBe('one');
  246. expect(viewView.basePath).toBe('two');
  247. viewView.createString('str');
  248. expect(viewView.get('str')).toBe(view.get('two.str'));
  249. expect(viewView.get('str')).toBe(db.get('one.two.str'));
  250. });
  251. });
  252. describe('#dispose', () => {
  253. it('should dispose of the resources used by the model', () => {
  254. const db = new ModelDB();
  255. const str = db.createString('str');
  256. const view = db.view('base');
  257. const str2 = view.createString('str');
  258. expect(db.isDisposed).toBe(false);
  259. expect(str.isDisposed).toBe(false);
  260. expect(view.isDisposed).toBe(false);
  261. expect(str2.isDisposed).toBe(false);
  262. db.dispose();
  263. expect(db.isDisposed).toBe(true);
  264. expect(str.isDisposed).toBe(true);
  265. expect(view.isDisposed).toBe(true);
  266. expect(str2.isDisposed).toBe(true);
  267. });
  268. it('should not dispose of resources in base databases', () => {
  269. const db = new ModelDB();
  270. const view = db.view('base');
  271. const str = db.createString('str');
  272. const str2 = view.createString('str');
  273. expect(db.isDisposed).toBe(false);
  274. expect(str.isDisposed).toBe(false);
  275. expect(view.isDisposed).toBe(false);
  276. expect(str2.isDisposed).toBe(false);
  277. view.dispose();
  278. expect(view.isDisposed).toBe(true);
  279. expect(str2.isDisposed).toBe(true);
  280. expect(db.isDisposed).toBe(false);
  281. expect(str.isDisposed).toBe(false);
  282. });
  283. it('should be safe to call more than once', () => {
  284. const db = new ModelDB();
  285. expect(db.isDisposed).toBe(false);
  286. db.dispose();
  287. expect(db.isDisposed).toBe(true);
  288. });
  289. });
  290. });
  291. });