浏览代码

Merge pull request #1166 from afshin/console-tests

Console tests and foreign handler fixes.
Steven Silvester 8 年之前
父节点
当前提交
5b0d813560

+ 7 - 7
src/completer/widget.ts

@@ -434,7 +434,7 @@ class CompleterWidget extends Widget {
       return;
     }
 
-    // Clear any previous set max-height.
+    // Clear any previously set max-height.
     node.style.maxHeight = '';
 
     // Clear any programmatically set margin-top.
@@ -443,16 +443,16 @@ class CompleterWidget extends Widget {
     // Make sure the node is visible.
     node.classList.remove(OUTOFVIEW_CLASS);
 
-    // Always use original coordinates to calculate completer position.
+    // Always use the original coordinates to calculate completer position.
     let { coords, chWidth, chHeight } = model.original;
     let style = window.getComputedStyle(node);
     let innerHeight = window.innerHeight;
     let scrollDelta = this._anchorPoint - this._anchor.scrollTop;
     let spaceAbove = coords.top + scrollDelta;
     let spaceBelow = innerHeight - coords.bottom - scrollDelta;
-    let marginTop = (parseInt(style.marginTop, 10) || 0);
-    let maxHeight = (parseInt(style.maxHeight, 10) || MAX_HEIGHT);
-    let minHeight = (parseInt(style.minHeight, 10) || MIN_HEIGHT);
+    let marginTop = parseInt(style.marginTop, 10) || 0;
+    let maxHeight = parseInt(style.maxHeight, 10) || MAX_HEIGHT;
+    let minHeight = parseInt(style.minHeight, 10) || MIN_HEIGHT;
     let anchorRect = this._anchor.getBoundingClientRect();
     let top: number;
 
@@ -471,8 +471,8 @@ class CompleterWidget extends Widget {
 
     // Make sure the completer ought to be visible.
     let withinBounds = maxHeight > minHeight &&
-                   spaceBelow >= chHeight &&
-                   spaceAbove >= anchorRect.top;
+                       spaceBelow >= chHeight &&
+                       spaceAbove >= anchorRect.top;
     if (!withinBounds) {
       node.classList.add(OUTOFVIEW_CLASS);
       return;

+ 29 - 10
src/console/foreign.ts

@@ -28,11 +28,21 @@ class ForeignHandler implements IDisposable {
    * Construct a new foreign message handler.
    */
   constructor(options: ForeignHandler.IOptions) {
+    this.kernel = options.kernel;
     this._renderer = options.renderer.createCell;
-    this._kernel = options.kernel;
     this._parent = options.parent;
   }
 
+  /**
+   * Set whether the handler is able to inject foreign cells into a console.
+   */
+  get enabled(): boolean {
+    return this._enabled;
+  }
+  set enabled(value: boolean) {
+    this._enabled = value;
+  }
+
   /**
    * Test whether the handler is disposed.
    */
@@ -78,13 +88,20 @@ class ForeignHandler implements IDisposable {
 
   /**
    * Handler IOPub messages.
+   *
+   * @returns `true` if the message resulted in a new cell injection or a
+   * previously injected cell being updated and `false` for all other messages.
    */
-  protected onIOPubMessage(sender: Kernel.IKernel, msg: KernelMessage.IIOPubMessage) {
+  protected onIOPubMessage(sender: Kernel.IKernel, msg: KernelMessage.IIOPubMessage): boolean {
+    // Only process messages if foreign cell injection is enabled.
+    if (!this._enabled) {
+      return false;
+    }
     // Check whether this message came from an external session.
     let parent = this._parent;
     let session = (msg.parent_header as KernelMessage.IHeader).session;
     if (session === this._kernel.clientId) {
-      return;
+      return false;
     }
     let msgType = msg.header.msg_type;
     let parentHeader = msg.parent_header as KernelMessage.IHeader;
@@ -98,29 +115,30 @@ class ForeignHandler implements IDisposable {
       cell.model.source = inputMsg.content.code;
       cell.trusted = true;
       parent.update();
-      break;
+      return true;
     case 'execute_result':
     case 'display_data':
     case 'stream':
     case 'error':
-      if (!(parentMsgId in this._cells)) {
+      if (!this._cells.has(parentMsgId)) {
         // This is an output from an input that was broadcast before our
         // session started listening. We will ignore it.
         console.warn('Ignoring output with no associated input cell.');
-        break;
+        return false;
       }
-      cell = this._cells.get(parentMsgId);
       let output = msg.content as nbformat.IOutput;
+      cell = this._cells.get(parentMsgId);
       output.output_type = msgType as nbformat.OutputType;
       cell.model.outputs.add(output);
       parent.update();
-      break;
+      return true;
     case 'clear_output':
       let wait = (msg as KernelMessage.IClearOutputMsg).content.wait;
+      cell = this._cells.get(parentMsgId);
       cell.model.outputs.clear(wait);
-      break;
+      return true;
     default:
-      break;
+      return false;
     }
   }
 
@@ -135,6 +153,7 @@ class ForeignHandler implements IDisposable {
   }
 
   private _cells = new Map<string, CodeCellWidget>();
+  private _enabled = true;
   private _isDisposed = false;
   private _kernel: Kernel.IKernel = null;
   private _parent: Panel = null;

+ 0 - 4
src/console/panel.ts

@@ -13,10 +13,6 @@ import {
   Panel
 } from 'phosphor/lib/ui/panel';
 
-import {
-  showDialog
-} from '../dialog';
-
 import {
   IRenderMime
 } from '../rendermime';

+ 6 - 4
test/src/console/content.spec.ts

@@ -4,7 +4,7 @@
 import expect = require('expect.js');
 
 import {
-  KernelMessage, utils, Session
+  KernelMessage, Session, utils
 } from '@jupyterlab/services';
 
 import {
@@ -49,11 +49,15 @@ import {
 
 
 class TestContent extends ConsoleContent {
+
   readonly edgeRequested: ISignal<this, void>;
 
   methods: string[] = [];
 
   dispose(): void {
+    if (this.isDisposed) {
+      return;
+    }
     super.dispose();
     clearSignalData(this);
   }
@@ -112,8 +116,6 @@ class TestHistory extends ConsoleHistory {
 
 defineSignal(TestHistory.prototype, 'ready');
 
-
-const CONSOLE_CLASS = 'jp-ConsoleContent';
 const renderer = CodeMirrorConsoleRenderer.defaultRenderer;
 const rendermime = defaultRenderMime();
 
@@ -129,7 +131,7 @@ describe('console/content', () => {
           let widget = new ConsoleContent({ renderer, rendermime, session });
           Widget.attach(widget, document.body);
           expect(widget).to.be.a(ConsoleContent);
-          expect(widget.node.classList.contains(CONSOLE_CLASS)).to.be(true);
+          expect(widget.node.classList).to.contain('jp-ConsoleContent');
           widget.dispose();
           done();
         }).catch(done);

+ 298 - 0
test/src/console/foreign.spec.ts

@@ -0,0 +1,298 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import expect = require('expect.js');
+
+import {
+  Kernel, KernelMessage, utils, Session
+} from '@jupyterlab/services';
+
+import {
+  clearSignalData, defineSignal, ISignal
+} from 'phosphor/lib/core/signaling';
+
+import {
+  Panel
+} from 'phosphor/lib/ui/panel';
+
+import {
+  CodeMirrorConsoleRenderer
+} from '../../../lib/console/codemirror/widget';
+
+import {
+  ForeignHandler
+} from '../../../lib/console/foreign';
+
+import {
+  CodeCellModel, CodeCellWidget
+} from '../../../lib/notebook/cells';
+
+import {
+  defaultRenderMime
+} from '../utils';
+
+
+const relevantTypes = [
+  'execute_input',
+  'execute_result',
+  'display_data',
+  'stream',
+  'error',
+  'clear_output'
+].reduce((acc, val) => {
+  acc.add(val);
+  return acc;
+}, new Set<string>());
+
+
+class TestHandler extends ForeignHandler {
+
+  readonly injected: ISignal<this, void>;
+
+  readonly received: ISignal<this, void>;
+
+  readonly rejected: ISignal<this, void>;
+
+  methods: string[] = [];
+
+  dispose(): void {
+    if (this.isDisposed) {
+      return;
+    }
+    super.dispose();
+    clearSignalData(this);
+  }
+
+  protected onIOPubMessage(sender: Kernel.IKernel, msg: KernelMessage.IIOPubMessage): boolean {
+    let injected = super.onIOPubMessage(sender, msg);
+    this.received.emit(void 0);
+    if (injected) {
+      this.injected.emit(void 0);
+    } else {
+      // If the message was not injected but otherwise would have been, emit
+      // a rejected signal. This should only happen if `enabled` is `false`.
+      let session = (msg.parent_header as KernelMessage.IHeader).session;
+      let msgType = msg.header.msg_type;
+      if (session !== this.kernel.clientId && relevantTypes.has(msgType)) {
+        this.rejected.emit(void 0);
+      }
+    }
+    return injected;
+  }
+}
+
+
+defineSignal(TestHandler.prototype, 'injected');
+defineSignal(TestHandler.prototype, 'received');
+defineSignal(TestHandler.prototype, 'rejected');
+
+
+const rendermime = defaultRenderMime();
+const renderer: ForeignHandler.IRenderer = {
+  createCell: () => {
+    let renderer = CodeMirrorConsoleRenderer.defaultCodeCellRenderer;
+    let cell = new CodeCellWidget({ rendermime, renderer });
+    cell.model = new CodeCellModel();
+    return cell;
+  }
+};
+
+
+describe('console/foreign', () => {
+
+  describe('ForeignHandler', () => {
+
+    describe('#constructor()', () => {
+
+      it('should create a new foreign handler', () => {
+        let handler = new ForeignHandler({
+          kernel: null,
+          parent: null,
+          renderer
+        });
+        expect(handler).to.be.a(ForeignHandler);
+      });
+
+    });
+
+    describe('#enabled', () => {
+
+      let a: Session.ISession;
+      let b: Session.ISession;
+      let handler: TestHandler;
+      let parent: Panel;
+
+      beforeEach(done => {
+        let path = utils.uuid();
+        let sessions = [Session.startNew({ path }), Session.startNew({ path })];
+        parent = new Panel();
+        Promise.all(sessions).then(([one, two]) => {
+          a = one;
+          b = two;
+          handler = new TestHandler({ kernel: a.kernel, parent, renderer });
+          done();
+        }).catch(done);
+      });
+
+      afterEach(done => {
+        parent.dispose();
+        handler.dispose();
+        a.shutdown().then(() => {
+          a.dispose();
+          b.dispose();
+          done();
+        }).catch(done);
+      });
+
+      it('should default to `true`', () => {
+        expect(handler.enabled).to.be(true);
+      });
+
+      it('should allow foreign cells to be injected if `true`', done => {
+        let code = 'print("#enabled:true")';
+        handler.injected.connect(() => { done(); });
+        b.kernel.execute({ code, stop_on_error: true });
+      });
+
+      it('should reject foreign cells if `false`', done => {
+        let code = 'print("#enabled:false")';
+        handler.enabled = false;
+        handler.rejected.connect(() => { done(); });
+        b.kernel.execute({ code, stop_on_error: true });
+      });
+
+    });
+
+    describe('#isDisposed', () => {
+
+      it('should indicate whether the handler is disposed', () => {
+        let handler = new ForeignHandler({
+          kernel: null,
+          parent: null,
+          renderer
+        });
+        expect(handler.isDisposed).to.be(false);
+        handler.dispose();
+        expect(handler.isDisposed).to.be(true);
+      });
+
+    });
+
+    describe('#kernel', () => {
+
+      it('should be set upon instantiation', () => {
+        let handler = new ForeignHandler({
+          kernel: null,
+          parent: null,
+          renderer
+        });
+        expect(handler.kernel).to.be(null);
+      });
+
+      it('should be resettable', done => {
+        let parent = new Panel();
+        let handler = new TestHandler({ kernel: null, parent, renderer });
+        Session.startNew({ path: utils.uuid() }).then(session => {
+          expect(handler.kernel).to.be(null);
+          handler.kernel = session.kernel;
+          expect(handler.kernel).to.be(session.kernel);
+          session.dispose();
+          handler.dispose();
+          done();
+        }).catch(done);
+      });
+
+    });
+
+    describe('#dispose()', () => {
+
+      it('should dispose the resources held by the handler', () => {
+        let handler = new ForeignHandler({
+          kernel: null,
+          parent: null,
+          renderer
+        });
+        expect(handler.isDisposed).to.be(false);
+        handler.dispose();
+        expect(handler.isDisposed).to.be(true);
+      });
+
+      it('should be safe to call multiple times', () => {
+        let handler = new ForeignHandler({
+          kernel: null,
+          parent: null,
+          renderer
+        });
+        expect(handler.isDisposed).to.be(false);
+        handler.dispose();
+        handler.dispose();
+        expect(handler.isDisposed).to.be(true);
+      });
+
+    });
+
+    describe('#onIOPubMessage()', () => {
+
+      let a: Session.ISession;
+      let b: Session.ISession;
+      let handler: TestHandler;
+      let parent: Panel;
+
+      beforeEach(done => {
+        let path = utils.uuid();
+        let sessions = [Session.startNew({ path }), Session.startNew({ path })];
+        parent = new Panel();
+        Promise.all(sessions).then(([one, two]) => {
+          a = one;
+          b = two;
+          handler = new TestHandler({ kernel: a.kernel, parent, renderer });
+          done();
+        }).catch(done);
+      });
+
+      afterEach(done => {
+        parent.dispose();
+        handler.dispose();
+        a.shutdown().then(() => {
+          a.dispose();
+          b.dispose();
+          done();
+        }).catch(done);
+      });
+
+      it('should be called when messages come through', done => {
+        let code = 'print("onIOPubMessage:disabled")';
+        handler.enabled = false;
+        handler.received.connect(() => { done(); });
+        b.kernel.execute({ code, stop_on_error: true });
+      });
+
+      it('should inject relevant cells into the parent', done => {
+        let code = 'print("onIOPubMessage:enabled")';
+        expect(parent.widgets.length).to.be(0);
+        handler.injected.connect(() => {
+          expect(parent.widgets.length).to.be.greaterThan(0);
+          done();
+        });
+        b.kernel.execute({ code, stop_on_error: true });
+      });
+
+      it('should not reject relevant iopub messages', done => {
+        let code = 'print("#onIOPubMessage:relevant")';
+        let called = 0;
+        handler.rejected.connect(() => {
+          done(new Error('rejected relevant iopub message'));
+        });
+        handler.injected.connect(() => {
+          if (++called === 2) {
+            done();
+          }
+        });
+        b.kernel.execute({ code, stop_on_error: true });
+      });
+
+    });
+
+  });
+
+});

+ 1 - 0
test/src/console/history.spec.ts

@@ -30,6 +30,7 @@ const mockHistory: KernelMessage.IHistoryReplyMsg = {
 
 
 class TestHistory extends ConsoleHistory {
+
   onHistory(value: KernelMessage.IHistoryReplyMsg): void {
     super.onHistory(value);
   }

+ 46 - 0
test/src/console/panel.spec.ts

@@ -0,0 +1,46 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import expect = require('expect.js');
+
+import {
+  Session, utils
+} from '@jupyterlab/services';
+
+import {
+  CodeMirrorConsoleRenderer
+} from '../../../lib/console/codemirror/widget';
+
+import {
+  ConsolePanel
+} from '../../../lib/console/panel';
+
+import {
+  defaultRenderMime
+} from '../utils';
+
+
+const renderer = CodeMirrorConsoleRenderer.defaultRenderer;
+const rendermime = defaultRenderMime();
+
+
+describe('console/panel', () => {
+
+  describe('ConsolePanel', () => {
+
+    describe('#constructor()', () => {
+
+      it('should create a new console panel', done => {
+        Session.startNew({ path: utils.uuid() }).then(session => {
+          let panel = new ConsolePanel({ renderer, rendermime, session });
+          expect(panel).to.be.a(ConsolePanel);
+          expect(panel.node.classList).to.contain('jp-ConsolePanel');
+          done();
+        });
+      });
+
+    });
+
+  });
+
+});

+ 2 - 0
test/src/index.ts

@@ -11,7 +11,9 @@ import './completer/model.spec';
 import './completer/widget.spec';
 
 import './console/content.spec';
+import './console/foreign.spec';
 import './console/history.spec';
+import './console/panel.spec';
 
 import './dialog/dialog.spec';
 

+ 53 - 39
test/src/notebook/cells/widget.spec.ts

@@ -7,10 +7,6 @@ import {
   Kernel
 } from '@jupyterlab/services';
 
-import {
-  JSONObject
-} from 'phosphor/lib/algorithm/json';
-
 import {
   Message, sendMessage
 } from 'phosphor/lib/core/messaging';
@@ -19,16 +15,16 @@ import {
   Widget, WidgetMessage
 } from 'phosphor/lib/ui/widget';
 
-import {
-  RenderMime
-} from '../../../../lib/rendermime';
-
 import {
   BaseCellWidget, CellModel, InputAreaWidget, ICellModel,
   CodeCellWidget, CodeCellModel, MarkdownCellWidget,
   RawCellWidget
 } from '../../../../lib/notebook/cells';
 
+import {
+  ICellEditorWidget
+} from '../../../../lib/notebook/cells/editor';
+
 import {
   CodeMirrorCellEditorWidget
 } from '../../../../lib/notebook/codemirror/cells/editor';
@@ -46,9 +42,8 @@ import {
 } from '../../../../lib/notebook/output-area';
 
 import {
-  ICellEditorWidget
-} from '../../../../lib/notebook/cells/editor';
-
+  RenderMime
+} from '../../../../lib/rendermime';
 
 import {
   defaultRenderMime
@@ -69,9 +64,7 @@ class LogBaseCell extends BaseCellWidget {
   methods: string[] = [];
 
   constructor() {
-    super({
-      renderer: CodeMirrorCodeCellWidgetRenderer.defaultRenderer
-    });
+    super({ renderer: CodeMirrorCodeCellWidgetRenderer.defaultRenderer });
   }
 
   protected onAfterAttach(msg: Message): void {
@@ -401,7 +394,8 @@ describe('notebook/cells/widget', () => {
     describe('#toggleInput()', () => {
 
       it('should toggle whether the input is shown', () => {
-        let widget = new BaseCellWidget({renderer: CodeMirrorCodeCellWidgetRenderer.defaultRenderer});
+        let renderer = CodeMirrorCodeCellWidgetRenderer.defaultRenderer;
+        let widget = new BaseCellWidget({ renderer });
         let input = widget.node.getElementsByClassName(INPUT_CLASS)[0];
         Widget.attach(widget, document.body);
         expect(window.getComputedStyle(input).display).to.not.be('none');
@@ -416,13 +410,15 @@ describe('notebook/cells/widget', () => {
     describe('#dispose()', () => {
 
       it('should dispose of the resources held by the widget', () => {
-        let widget = new BaseCellWidget({renderer: CodeMirrorCodeCellWidgetRenderer.defaultRenderer});
+        let renderer = CodeMirrorCodeCellWidgetRenderer.defaultRenderer;
+        let widget = new BaseCellWidget({ renderer });
         widget.dispose();
         expect(widget.isDisposed).to.be(true);
       });
 
       it('should be safe to call multiple times', () => {
-        let widget = new BaseCellWidget({renderer: CodeMirrorCodeCellWidgetRenderer.defaultRenderer});
+        let renderer = CodeMirrorCodeCellWidgetRenderer.defaultRenderer;
+        let widget = new BaseCellWidget({ renderer });
         widget.dispose();
         widget.dispose();
         expect(widget.isDisposed).to.be(true);
@@ -530,8 +526,8 @@ describe('notebook/cells/widget', () => {
       describe('#defaultRenderer', () => {
 
         it('should be a renderer', () => {
-          let defaultRenderer = CodeMirrorCodeCellWidgetRenderer.defaultRenderer;
-          expect(defaultRenderer).to.be.a(BaseCellWidget.Renderer);
+          let renderer = CodeMirrorCodeCellWidgetRenderer.defaultRenderer;
+          expect(renderer).to.be.a(BaseCellWidget.Renderer);
         });
 
       });
@@ -545,7 +541,8 @@ describe('notebook/cells/widget', () => {
     describe('#constructor()', () => {
 
       it('should create a code cell widget', () => {
-        let widget = new CodeCellWidget({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultCodeCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultCodeCellRenderer;
+        let widget = new CodeCellWidget({ rendermime, renderer });
         expect(widget).to.be.a(CodeCellWidget);
       });
 
@@ -570,13 +567,15 @@ describe('notebook/cells/widget', () => {
     describe('#dispose()', () => {
 
       it('should dispose of the resources held by the widget', () => {
-        let widget = new CodeCellWidget({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultCodeCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultCodeCellRenderer;
+        let widget = new CodeCellWidget({ rendermime, renderer });
         widget.dispose();
         expect(widget.isDisposed).to.be(true);
       });
 
       it('should be safe to call multiple times', () => {
-        let widget = new CodeCellWidget({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultCodeCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultCodeCellRenderer;
+        let widget = new CodeCellWidget({ rendermime, renderer });
         widget.dispose();
         widget.dispose();
         expect(widget.isDisposed).to.be(true);
@@ -587,7 +586,8 @@ describe('notebook/cells/widget', () => {
     describe('#execute()', () => {
 
       it('should fulfill a promise if there is no code to execute', (done) => {
-        let widget = new CodeCellWidget({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultCodeCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultCodeCellRenderer;
+        let widget = new CodeCellWidget({ rendermime, renderer });
         Kernel.startNew().then(kernel => {
           widget.model = new CodeCellModel();
           return widget.execute(kernel).then(() => {
@@ -598,7 +598,8 @@ describe('notebook/cells/widget', () => {
       });
 
       it('should fulfill a promise if there is code to execute', (done) => {
-        let widget = new CodeCellWidget({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultCodeCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultCodeCellRenderer;
+        let widget = new CodeCellWidget({ rendermime, renderer });
         Kernel.startNew().then(kernel => {
           widget.model = new CodeCellModel();
           widget.model.source = 'foo';
@@ -618,7 +619,8 @@ describe('notebook/cells/widget', () => {
     describe('#onUpdateRequest()', () => {
 
       it('should update the widget', () => {
-        let widget = new LogCodeCell({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultCodeCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultCodeCellRenderer;
+        let widget = new LogCodeCell({ rendermime, renderer });
         expect(widget.methods).to.not.contain('onUpdateRequest');
         sendMessage(widget, WidgetMessage.UpdateRequest);
         expect(widget.methods).to.contain('onUpdateRequest');
@@ -630,7 +632,8 @@ describe('notebook/cells/widget', () => {
 
       it('should fire when the model changes', () => {
         let method = 'onModelChanged';
-        let widget = new LogCodeCell({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultCodeCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultCodeCellRenderer;
+        let widget = new LogCodeCell({ rendermime, renderer });
         expect(widget.methods).to.not.contain(method);
         widget.model = new CodeCellModel();
         expect(widget.methods).to.contain(method);
@@ -642,7 +645,8 @@ describe('notebook/cells/widget', () => {
 
       it('should fire when model state changes', () => {
         let method = 'onModelStateChanged';
-        let widget = new LogCodeCell({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultCodeCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultCodeCellRenderer;
+        let widget = new LogCodeCell({ rendermime, renderer });
         widget.model = new CodeCellModel();
         expect(widget.methods).to.not.contain(method);
         widget.model.source = 'foo';
@@ -655,7 +659,8 @@ describe('notebook/cells/widget', () => {
 
       it('should fire when model metadata changes', () => {
         let method = 'onMetadataChanged';
-        let widget = new LogCodeCell({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultCodeCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultCodeCellRenderer;
+        let widget = new LogCodeCell({ rendermime, renderer });
         widget.model = new CodeCellModel();
         expect(widget.methods).to.not.contain(method);
         widget.model.metadataChanged.emit({
@@ -692,8 +697,8 @@ describe('notebook/cells/widget', () => {
       describe('#defaultRenderer', () => {
 
         it('should be a renderer', () => {
-          let defaultRenderer = CodeMirrorNotebookRenderer.defaultCodeCellRenderer;
-          expect(defaultRenderer).to.be.a(CodeCellWidget.Renderer);
+          let renderer = CodeMirrorNotebookRenderer.defaultCodeCellRenderer;
+          expect(renderer).to.be.a(CodeCellWidget.Renderer);
         });
 
       });
@@ -707,7 +712,8 @@ describe('notebook/cells/widget', () => {
     describe('#constructor()', () => {
 
       it('should create a markdown cell widget', () => {
-        let widget = new MarkdownCellWidget({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer;
+        let widget = new MarkdownCellWidget({ rendermime, renderer });
         expect(widget).to.be.a(MarkdownCellWidget);
       });
 
@@ -725,7 +731,8 @@ describe('notebook/cells/widget', () => {
       });
 
       it('should set the default mimetype to text/x-ipythongfm', () => {
-        let widget = new MarkdownCellWidget({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer;
+        let widget = new MarkdownCellWidget({ rendermime, renderer });
         expect(widget.mimetype).to.be('text/x-ipythongfm');
       });
 
@@ -734,7 +741,8 @@ describe('notebook/cells/widget', () => {
     describe('#rendered', () => {
 
       it('should default to true', (done) => {
-        let widget = new MarkdownCellWidget({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer;
+        let widget = new MarkdownCellWidget({ rendermime, renderer });
         Widget.attach(widget, document.body);
         expect(widget.rendered).to.be(true);
         requestAnimationFrame(() => {
@@ -745,7 +753,8 @@ describe('notebook/cells/widget', () => {
       });
 
       it('should unrender the widget', (done) => {
-        let widget = new MarkdownCellWidget({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer;
+        let widget = new MarkdownCellWidget({ rendermime, renderer });
         Widget.attach(widget, document.body);
         widget.rendered = false;
         requestAnimationFrame(() => {
@@ -756,7 +765,8 @@ describe('notebook/cells/widget', () => {
       });
 
       it('should ignore being set to the same value', (done) => {
-        let widget = new LogMarkdownCell({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer;
+        let widget = new LogMarkdownCell({ rendermime, renderer });
         Widget.attach(widget, document.body);
         widget.rendered = false;
         widget.rendered = false;
@@ -774,13 +784,15 @@ describe('notebook/cells/widget', () => {
     describe('#dispose()', () => {
 
       it('should dispose of the resources held by the widget', () => {
-        let widget = new MarkdownCellWidget({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer;
+        let widget = new MarkdownCellWidget({ rendermime, renderer });
         widget.dispose();
         expect(widget.isDisposed).to.be(true);
       });
 
       it('should be safe to call multiple times', () => {
-        let widget = new MarkdownCellWidget({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer;
+        let widget = new MarkdownCellWidget({ rendermime, renderer });
         widget.dispose();
         widget.dispose();
         expect(widget.isDisposed).to.be(true);
@@ -791,7 +803,8 @@ describe('notebook/cells/widget', () => {
     describe('#onUpdateRequest()', () => {
 
       it('should update the widget', () => {
-        let widget = new LogMarkdownCell({ rendermime, renderer: CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer });
+        let renderer = CodeMirrorNotebookRenderer.defaultMarkdownCellRenderer;
+        let widget = new LogMarkdownCell({ rendermime, renderer });
         expect(widget.methods).to.not.contain('onUpdateRequest');
         sendMessage(widget, WidgetMessage.UpdateRequest);
         expect(widget.methods).to.contain('onUpdateRequest');
@@ -806,7 +819,8 @@ describe('notebook/cells/widget', () => {
     describe('#constructor()', () => {
 
       it('should create a raw cell widget', () => {
-        let widget = new RawCellWidget({renderer: CodeMirrorNotebookRenderer.defaultRawCellRenderer});
+        let renderer = CodeMirrorNotebookRenderer.defaultRawCellRenderer;
+        let widget = new RawCellWidget({ renderer });
         expect(widget).to.be.a(RawCellWidget);
       });
 

+ 1 - 1
test/src/tsconfig.json

@@ -2,7 +2,7 @@
   "compilerOptions": {
     "noImplicitAny": true,
     "noEmitOnError": true,
-    "lib": ["dom", "es5", "es2015.promise"],
+    "lib": ["dom", "es5", "es2015.collection", "es2015.promise"],
     "module": "commonjs",
     "moduleResolution": "node",
     "target": "ES5",