widget.spec.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import { LoggerRegistry, LogConsolePanel } from '@jupyterlab/logconsole';
  4. import {
  5. RenderMimeRegistry,
  6. IRenderMimeRegistry,
  7. standardRendererFactories as initialFactories
  8. } from '@jupyterlab/rendermime';
  9. import { Signal, ISignal } from '@lumino/signaling';
  10. import { Widget } from '@lumino/widgets';
  11. class SignalLogger<SENDER, ARGS> {
  12. constructor(signal: ISignal<SENDER, ARGS>) {
  13. signal.connect(this.slot, this);
  14. }
  15. slot(sender: SENDER, args: ARGS) {
  16. this.args.push(args);
  17. }
  18. clear() {
  19. this.args.length = 0;
  20. }
  21. dispose() {
  22. Signal.disconnectAll(this);
  23. }
  24. args: ARGS[] = [];
  25. }
  26. function anyAncestor(el: Element, testFn: (el: Element) => boolean) {
  27. while (el) {
  28. if (testFn(el)) {
  29. return true;
  30. }
  31. if (!el.parentElement || el === el.parentNode) {
  32. break;
  33. }
  34. el = el.parentElement;
  35. }
  36. return false;
  37. }
  38. function isHiddenLumino(el: Element) {
  39. return el.classList.contains('lm-mod-hidden');
  40. }
  41. describe('LogConsolePanel', () => {
  42. let defaultRendermime: IRenderMimeRegistry;
  43. let registry: LoggerRegistry;
  44. let logConsole: LogConsolePanel;
  45. beforeEach(() => {
  46. defaultRendermime = new RenderMimeRegistry({ initialFactories });
  47. registry = new LoggerRegistry({
  48. defaultRendermime,
  49. maxLength: 10
  50. });
  51. logConsole = new LogConsolePanel(registry);
  52. });
  53. afterEach(() => {
  54. registry.dispose();
  55. logConsole.dispose();
  56. });
  57. describe('#constructor()', () => {
  58. it('should create a console with initial parameters', () => {
  59. expect(logConsole).toBeInstanceOf(LogConsolePanel);
  60. expect(logConsole.loggerRegistry).toBe(registry);
  61. });
  62. });
  63. describe('#loggerRegistry', () => {
  64. it('returns the logger registry', () => {
  65. expect(logConsole.loggerRegistry).toBe(registry);
  66. });
  67. });
  68. describe('#source', () => {
  69. it('sets the current source', () => {
  70. expect(logConsole.source).toBe(null);
  71. registry.getLogger('A');
  72. logConsole.source = 'A';
  73. expect(logConsole.source).toBe('A');
  74. });
  75. it('displays output only from the current source', () => {
  76. const loggerA = registry.getLogger('A');
  77. const loggerB = registry.getLogger('B');
  78. loggerA.log({
  79. type: 'html',
  80. data: '<div id="A"></div>',
  81. level: 'warning'
  82. });
  83. loggerB.log({
  84. type: 'html',
  85. data: '<div id="B"></div>',
  86. level: 'warning'
  87. });
  88. logConsole.source = 'A';
  89. const nodeA = logConsole.node.querySelector('#A')!;
  90. const nodeB = logConsole.node.querySelector('#B')!;
  91. expect(nodeA).not.toBeNull();
  92. expect(anyAncestor(nodeA, isHiddenLumino)).toBe(false);
  93. expect(nodeB).not.toBeNull();
  94. expect(anyAncestor(nodeB, isHiddenLumino)).toBe(true);
  95. logConsole.source = 'B';
  96. expect(anyAncestor(nodeA, isHiddenLumino)).toBe(true);
  97. expect(anyAncestor(nodeB, isHiddenLumino)).toBe(false);
  98. });
  99. it('emits a source changed signal if changed', () => {
  100. const s = new SignalLogger(logConsole.sourceChanged);
  101. logConsole.source = 'A';
  102. logConsole.source = null;
  103. expect(s.args).toEqual([
  104. { name: 'source', oldValue: null, newValue: 'A' },
  105. { name: 'source', oldValue: 'A', newValue: null }
  106. ]);
  107. s.dispose();
  108. });
  109. it('has no effect if not changed', () => {
  110. const s = new SignalLogger(logConsole.sourceChanged);
  111. logConsole.source = null;
  112. expect(s.args).toEqual([]);
  113. registry.getLogger('A');
  114. logConsole.source = 'A';
  115. s.clear();
  116. logConsole.source = 'A';
  117. expect(s.args).toEqual([]);
  118. s.dispose();
  119. });
  120. });
  121. describe('#sourceVersion', () => {
  122. it('gives the version for the current source', () => {
  123. const A = registry.getLogger('A');
  124. A.log({ type: 'text', data: 'message', level: 'warning' });
  125. A.log({ type: 'text', data: 'message', level: 'warning' });
  126. logConsole.source = 'A';
  127. expect(logConsole.sourceVersion).toBe(A.version);
  128. });
  129. it('is null if the source is null', () => {
  130. expect(logConsole.source).toBe(null);
  131. expect(logConsole.sourceVersion).toBe(null);
  132. });
  133. });
  134. describe('#logger', () => {
  135. it('gives the logger for the current source', () => {
  136. const A = registry.getLogger('A');
  137. A.log({ type: 'text', data: 'message', level: 'warning' });
  138. A.log({ type: 'text', data: 'message', level: 'warning' });
  139. logConsole.source = 'A';
  140. expect(logConsole.logger).toBe(A);
  141. });
  142. it('is null if the source is null', () => {
  143. expect(logConsole.source).toBe(null);
  144. expect(logConsole.logger).toBe(null);
  145. });
  146. });
  147. describe('#sourceDisplayed', () => {
  148. it('emits when console is attached', () => {
  149. const s = new SignalLogger(logConsole.sourceDisplayed);
  150. const loggerA = registry.getLogger('A');
  151. loggerA.log({ type: 'text', data: 'A1', level: 'warning' });
  152. logConsole.source = 'A';
  153. expect(s.args).toEqual([]);
  154. Widget.attach(logConsole, document.body);
  155. expect(s.args).toEqual([{ source: 'A', version: 1 }]);
  156. s.dispose();
  157. });
  158. it('emits when console is shown', () => {
  159. const s = new SignalLogger(logConsole.sourceDisplayed);
  160. const loggerA = registry.getLogger('A');
  161. loggerA.log({ type: 'text', data: 'A1', level: 'warning' });
  162. logConsole.source = 'A';
  163. logConsole.hide();
  164. Widget.attach(logConsole, document.body);
  165. expect(s.args).toEqual([]);
  166. logConsole.show();
  167. expect(s.args).toEqual([{ source: 'A', version: 1 }]);
  168. s.dispose();
  169. });
  170. it('emits when source is selected', () => {
  171. const s = new SignalLogger(logConsole.sourceDisplayed);
  172. const loggerA = registry.getLogger('A');
  173. const loggerB = registry.getLogger('B');
  174. loggerA.log({ type: 'text', data: 'A1', level: 'warning' });
  175. loggerB.log({ type: 'text', data: 'B1', level: 'warning' });
  176. Widget.attach(logConsole, document.body);
  177. expect(s.args).toEqual([]);
  178. logConsole.source = 'A';
  179. expect(s.args).toEqual([{ source: 'A', version: 1 }]);
  180. s.clear();
  181. loggerB.log({ type: 'text', data: 'B2', level: 'warning' });
  182. expect(s.args).toEqual([]);
  183. logConsole.source = 'B';
  184. expect(s.args).toEqual([{ source: 'B', version: 2 }]);
  185. s.dispose();
  186. });
  187. it('emits when logging to displayed source', () => {
  188. const s = new SignalLogger(logConsole.sourceDisplayed);
  189. const loggerA = registry.getLogger('A');
  190. loggerA.log({ type: 'text', data: 'A1', level: 'warning' });
  191. Widget.attach(logConsole, document.body);
  192. expect(s.args).toEqual([]);
  193. logConsole.source = 'A';
  194. expect(s.args).toEqual([{ source: 'A', version: 1 }]);
  195. s.clear();
  196. loggerA.log({ type: 'text', data: 'A2', level: 'warning' });
  197. expect(s.args).toEqual([{ source: 'A', version: 2 }]);
  198. s.dispose();
  199. });
  200. });
  201. });