history.spec.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import 'jest';
  4. import { ISessionContext } from '@jupyterlab/apputils';
  5. import { KernelMessage } from '@jupyterlab/services';
  6. import { CodeEditor } from '@jupyterlab/codeeditor';
  7. import { CodeMirrorEditor } from '@jupyterlab/codemirror';
  8. import { createSessionContext, signalToPromise } from '@jupyterlab/testutils';
  9. import { ConsoleHistory } from '../src';
  10. const mockHistory = ({
  11. header: null,
  12. parent_header: {
  13. date: '',
  14. msg_id: '',
  15. msg_type: 'history_request',
  16. username: '',
  17. session: '',
  18. version: '5.3'
  19. },
  20. metadata: null,
  21. buffers: null,
  22. channel: 'shell',
  23. content: {
  24. status: 'ok',
  25. history: [
  26. [0, 0, 'foo'],
  27. [0, 0, 'bar'],
  28. [0, 0, 'baz'],
  29. [0, 0, 'qux']
  30. ]
  31. }
  32. } as unknown) as KernelMessage.IHistoryReplyMsg;
  33. class TestHistory extends ConsoleHistory {
  34. methods: string[] = [];
  35. onEdgeRequest(
  36. editor: CodeEditor.IEditor,
  37. location: CodeEditor.EdgeLocation
  38. ): void {
  39. this.methods.push('onEdgeRequest');
  40. super.onEdgeRequest(editor, location);
  41. }
  42. onHistory(value: KernelMessage.IHistoryReplyMsg): void {
  43. super.onHistory(value);
  44. this.methods.push('onHistory');
  45. }
  46. onTextChange(): void {
  47. super.onTextChange();
  48. this.methods.push('onTextChange');
  49. }
  50. }
  51. describe('console/history', () => {
  52. let sessionContext: ISessionContext;
  53. beforeEach(async () => {
  54. sessionContext = await createSessionContext();
  55. });
  56. afterAll(() => sessionContext.shutdown());
  57. describe('ConsoleHistory', () => {
  58. describe('#constructor()', () => {
  59. it('should create a console history object', () => {
  60. const history = new ConsoleHistory({ sessionContext });
  61. expect(history).toBeInstanceOf(ConsoleHistory);
  62. });
  63. });
  64. describe('#isDisposed', () => {
  65. it('should get whether the object is disposed', () => {
  66. const history = new ConsoleHistory({ sessionContext });
  67. expect(history.isDisposed).toBe(false);
  68. history.dispose();
  69. expect(history.isDisposed).toBe(true);
  70. });
  71. });
  72. describe('#session', () => {
  73. it('should be the client session object', () => {
  74. const history = new ConsoleHistory({ sessionContext });
  75. expect(history.sessionContext).toBe(sessionContext);
  76. });
  77. });
  78. describe('#dispose()', () => {
  79. it('should dispose the history object', () => {
  80. const history = new ConsoleHistory({ sessionContext });
  81. expect(history.isDisposed).toBe(false);
  82. history.dispose();
  83. expect(history.isDisposed).toBe(true);
  84. });
  85. it('should be safe to dispose multiple times', () => {
  86. const history = new ConsoleHistory({ sessionContext });
  87. expect(history.isDisposed).toBe(false);
  88. history.dispose();
  89. history.dispose();
  90. expect(history.isDisposed).toBe(true);
  91. });
  92. });
  93. describe('#back()', () => {
  94. it('should return an empty string if no history exists', async () => {
  95. const history = new ConsoleHistory({ sessionContext });
  96. const result = await history.back('');
  97. expect(result).toBe('');
  98. });
  99. it('should return previous items if they exist', async () => {
  100. const history = new TestHistory({ sessionContext });
  101. history.onHistory(mockHistory);
  102. const result = await history.back('');
  103. if (mockHistory.content.status !== 'ok') {
  104. throw new Error('Test history reply is not an "ok" reply');
  105. }
  106. const index = mockHistory.content.history.length - 1;
  107. const last = (mockHistory.content.history[index] as any)[2];
  108. expect(result).toBe(last);
  109. });
  110. });
  111. describe('#forward()', () => {
  112. it('should return an empty string if no history exists', async () => {
  113. const history = new ConsoleHistory({ sessionContext });
  114. const result = await history.forward('');
  115. expect(result).toBe('');
  116. });
  117. it('should return next items if they exist', async () => {
  118. const history = new TestHistory({ sessionContext });
  119. history.onHistory(mockHistory);
  120. await Promise.all([history.back(''), history.back('')]);
  121. const result = await history.forward('');
  122. if (mockHistory.content.status !== 'ok') {
  123. throw new Error('Test history reply is not an "ok" reply');
  124. }
  125. const index = mockHistory.content.history.length - 1;
  126. const last = (mockHistory.content.history[index] as any)[2];
  127. expect(result).toBe(last);
  128. });
  129. });
  130. describe('#push()', () => {
  131. it('should allow addition of history items', async () => {
  132. const history = new ConsoleHistory({ sessionContext });
  133. const item = 'foo';
  134. history.push(item);
  135. const result = await history.back('');
  136. expect(result).toBe(item);
  137. });
  138. });
  139. describe('#onTextChange()', () => {
  140. it('should be called upon an editor text change', () => {
  141. const history = new TestHistory({ sessionContext });
  142. expect(history.methods).toEqual(
  143. expect.not.arrayContaining(['onTextChange'])
  144. );
  145. const model = new CodeEditor.Model();
  146. const host = document.createElement('div');
  147. const editor = new CodeMirrorEditor({ model, host });
  148. history.editor = editor;
  149. model.value.text = 'foo';
  150. expect(history.methods).toEqual(
  151. expect.arrayContaining(['onTextChange'])
  152. );
  153. });
  154. });
  155. describe('#onEdgeRequest()', () => {
  156. it('should be called upon an editor edge request', async () => {
  157. const history = new TestHistory({ sessionContext });
  158. expect(history.methods).toEqual(
  159. expect.not.arrayContaining(['onEdgeRequest'])
  160. );
  161. const host = document.createElement('div');
  162. const model = new CodeEditor.Model();
  163. const editor = new CodeMirrorEditor({ model, host });
  164. history.editor = editor;
  165. history.push('foo');
  166. const promise = signalToPromise(editor.model.value.changed);
  167. editor.edgeRequested.emit('top');
  168. expect(history.methods).toEqual(
  169. expect.arrayContaining(['onEdgeRequest'])
  170. );
  171. await promise;
  172. expect(editor.model.value.text).toBe('foo');
  173. });
  174. });
  175. });
  176. });