history.spec.ts 6.2 KB

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