history-manager-spec.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. const { HistoryManager, HistoryProject } = require('../src/history-manager');
  2. const StateStore = require('../src/state-store');
  3. describe('HistoryManager', () => {
  4. let historyManager, commandRegistry, project, stateStore;
  5. let commandDisposable, projectDisposable;
  6. beforeEach(async () => {
  7. commandDisposable = jasmine.createSpyObj('Disposable', ['dispose']);
  8. commandRegistry = jasmine.createSpyObj('CommandRegistry', ['add']);
  9. commandRegistry.add.andReturn(commandDisposable);
  10. stateStore = new StateStore('history-manager-test', 1);
  11. await stateStore.save('history-manager', {
  12. projects: [
  13. {
  14. paths: ['/1', 'c:\\2'],
  15. lastOpened: new Date(2016, 9, 17, 17, 16, 23)
  16. },
  17. { paths: ['/test'], lastOpened: new Date(2016, 9, 17, 11, 12, 13) }
  18. ]
  19. });
  20. projectDisposable = jasmine.createSpyObj('Disposable', ['dispose']);
  21. project = jasmine.createSpyObj('Project', ['onDidChangePaths']);
  22. project.onDidChangePaths.andCallFake(f => {
  23. project.didChangePathsListener = f;
  24. return projectDisposable;
  25. });
  26. historyManager = new HistoryManager({
  27. stateStore,
  28. project,
  29. commands: commandRegistry
  30. });
  31. await historyManager.loadState();
  32. });
  33. afterEach(async () => {
  34. await stateStore.clear();
  35. });
  36. describe('constructor', () => {
  37. it("registers the 'clear-project-history' command function", () => {
  38. expect(commandRegistry.add).toHaveBeenCalled();
  39. const cmdCall = commandRegistry.add.calls[0];
  40. expect(cmdCall.args.length).toBe(3);
  41. expect(cmdCall.args[0]).toBe('atom-workspace');
  42. expect(typeof cmdCall.args[1]['application:clear-project-history']).toBe(
  43. 'function'
  44. );
  45. });
  46. describe('getProjects', () => {
  47. it('returns an array of HistoryProjects', () => {
  48. expect(historyManager.getProjects()).toEqual([
  49. new HistoryProject(
  50. ['/1', 'c:\\2'],
  51. new Date(2016, 9, 17, 17, 16, 23)
  52. ),
  53. new HistoryProject(['/test'], new Date(2016, 9, 17, 11, 12, 13))
  54. ]);
  55. });
  56. it('returns an array of HistoryProjects that is not mutable state', () => {
  57. const firstProjects = historyManager.getProjects();
  58. firstProjects.pop();
  59. firstProjects[0].path = 'modified';
  60. const secondProjects = historyManager.getProjects();
  61. expect(secondProjects.length).toBe(2);
  62. expect(secondProjects[0].path).not.toBe('modified');
  63. });
  64. });
  65. describe('clearProjects', () => {
  66. it('clears the list of projects', async () => {
  67. expect(historyManager.getProjects().length).not.toBe(0);
  68. await historyManager.clearProjects();
  69. expect(historyManager.getProjects().length).toBe(0);
  70. });
  71. it('saves the state', async () => {
  72. await historyManager.clearProjects();
  73. const historyManager2 = new HistoryManager({
  74. stateStore,
  75. project,
  76. commands: commandRegistry
  77. });
  78. await historyManager2.loadState();
  79. expect(historyManager.getProjects().length).toBe(0);
  80. });
  81. it('fires the onDidChangeProjects event', async () => {
  82. const didChangeSpy = jasmine.createSpy();
  83. historyManager.onDidChangeProjects(didChangeSpy);
  84. await historyManager.clearProjects();
  85. expect(historyManager.getProjects().length).toBe(0);
  86. expect(didChangeSpy).toHaveBeenCalled();
  87. });
  88. });
  89. it('listens to project.onDidChangePaths adding a new project', () => {
  90. const start = new Date();
  91. project.didChangePathsListener(['/a/new', '/path/or/two']);
  92. const projects = historyManager.getProjects();
  93. expect(projects.length).toBe(3);
  94. expect(projects[0].paths).toEqual(['/a/new', '/path/or/two']);
  95. expect(projects[0].lastOpened).not.toBeLessThan(start);
  96. });
  97. it('listens to project.onDidChangePaths updating an existing project', () => {
  98. const start = new Date();
  99. project.didChangePathsListener(['/test']);
  100. const projects = historyManager.getProjects();
  101. expect(projects.length).toBe(2);
  102. expect(projects[0].paths).toEqual(['/test']);
  103. expect(projects[0].lastOpened).not.toBeLessThan(start);
  104. });
  105. });
  106. describe('loadState', () => {
  107. it('defaults to an empty array if no state', async () => {
  108. await stateStore.clear();
  109. await historyManager.loadState();
  110. expect(historyManager.getProjects()).toEqual([]);
  111. });
  112. it('defaults to an empty array if no projects', async () => {
  113. await stateStore.save('history-manager', {});
  114. await historyManager.loadState();
  115. expect(historyManager.getProjects()).toEqual([]);
  116. });
  117. });
  118. describe('addProject', () => {
  119. it('adds a new project to the end', async () => {
  120. const date = new Date(2010, 10, 9, 8, 7, 6);
  121. await historyManager.addProject(['/a/b'], date);
  122. const projects = historyManager.getProjects();
  123. expect(projects.length).toBe(3);
  124. expect(projects[2].paths).toEqual(['/a/b']);
  125. expect(projects[2].lastOpened).toBe(date);
  126. });
  127. it('adds a new project to the start', async () => {
  128. const date = new Date();
  129. await historyManager.addProject(['/so/new'], date);
  130. const projects = historyManager.getProjects();
  131. expect(projects.length).toBe(3);
  132. expect(projects[0].paths).toEqual(['/so/new']);
  133. expect(projects[0].lastOpened).toBe(date);
  134. });
  135. it('updates an existing project and moves it to the start', async () => {
  136. const date = new Date();
  137. await historyManager.addProject(['/test'], date);
  138. const projects = historyManager.getProjects();
  139. expect(projects.length).toBe(2);
  140. expect(projects[0].paths).toEqual(['/test']);
  141. expect(projects[0].lastOpened).toBe(date);
  142. });
  143. it('fires the onDidChangeProjects event when adding a project', async () => {
  144. const didChangeSpy = jasmine.createSpy();
  145. const beforeCount = historyManager.getProjects().length;
  146. historyManager.onDidChangeProjects(didChangeSpy);
  147. await historyManager.addProject(['/test-new'], new Date());
  148. expect(didChangeSpy).toHaveBeenCalled();
  149. expect(historyManager.getProjects().length).toBe(beforeCount + 1);
  150. });
  151. it('fires the onDidChangeProjects event when updating a project', async () => {
  152. const didChangeSpy = jasmine.createSpy();
  153. const beforeCount = historyManager.getProjects().length;
  154. historyManager.onDidChangeProjects(didChangeSpy);
  155. await historyManager.addProject(['/test'], new Date());
  156. expect(didChangeSpy).toHaveBeenCalled();
  157. expect(historyManager.getProjects().length).toBe(beforeCount);
  158. });
  159. });
  160. describe('getProject', () => {
  161. it('returns a project that matches the paths', () => {
  162. const project = historyManager.getProject(['/1', 'c:\\2']);
  163. expect(project).not.toBeNull();
  164. expect(project.paths).toEqual(['/1', 'c:\\2']);
  165. });
  166. it("returns null when it can't find the project", () => {
  167. const project = historyManager.getProject(['/1']);
  168. expect(project).toBeNull();
  169. });
  170. });
  171. describe('saveState', () => {
  172. let savedHistory;
  173. beforeEach(() => {
  174. // historyManager.saveState is spied on globally to prevent specs from
  175. // modifying the shared project history. Since these tests depend on
  176. // saveState, we unspy it but in turn spy on the state store instead
  177. // so that no data is actually stored to it.
  178. jasmine.unspy(historyManager, 'saveState');
  179. spyOn(historyManager.stateStore, 'save').andCallFake((name, history) => {
  180. savedHistory = history;
  181. return Promise.resolve();
  182. });
  183. });
  184. it('saves the state', async () => {
  185. await historyManager.addProject(['/save/state']);
  186. await historyManager.saveState();
  187. const historyManager2 = new HistoryManager({
  188. stateStore,
  189. project,
  190. commands: commandRegistry
  191. });
  192. spyOn(historyManager2.stateStore, 'load').andCallFake(name =>
  193. Promise.resolve(savedHistory)
  194. );
  195. await historyManager2.loadState();
  196. expect(historyManager2.getProjects()[0].paths).toEqual(['/save/state']);
  197. });
  198. });
  199. });