ソースを参照

Add notebook tools tests

And correct the inevitable errors that writing tests uncovered, such as a newly created tool not getting a notebook update message at the very start.
Jason Grout 6 年 前
コミット
01437e1760

+ 19 - 3
packages/notebook/src/notebooktools.ts

@@ -164,7 +164,8 @@ export class NotebookTools extends Widget implements INotebookTools {
     // consolidated into a single object, rather than a broad reference to this.
     tool.notebookTools = this;
 
-    // Trigger the tool to update its active cell.
+    // Trigger the tool to update its active notebook and cell.
+    MessageLoop.sendMessage(tool, NotebookTools.ActiveNotebookPanelMessage);
     MessageLoop.sendMessage(tool, NotebookTools.ActiveCellMessage);
   }
 
@@ -580,10 +581,21 @@ export namespace NotebookTools {
       super(options);
     }
 
+    /**
+     * Handle a change to the notebook.
+     */
+    protected onActiveNotebookPanelChanged(msg: Message): void {
+      this._update();
+    }
+
     /**
      * Handle a change to the notebook metadata.
      */
     protected onActiveNotebookPanelMetadataChanged(msg: Message): void {
+      this._update();
+    }
+
+    private _update() {
       const nb =
         this.notebookTools.activeNotebookPanel &&
         this.notebookTools.activeNotebookPanel.content;
@@ -604,13 +616,17 @@ export namespace NotebookTools {
      * Handle a change to the active cell.
      */
     protected onActiveCellChanged(msg: Message): void {
-      let cell = this.notebookTools.activeCell;
-      this.editor.source = cell ? cell.model.metadata : null;
+      this._update();
     }
+
     /**
      * Handle a change to the active cell metadata.
      */
     protected onActiveCellMetadataChanged(msg: Message): void {
+      this._update();
+    }
+
+    private _update() {
       let cell = this.notebookTools.activeCell;
       this.editor.source = cell ? cell.model.metadata : null;
     }

+ 103 - 9
tests/test-notebook/src/notebooktools.spec.ts

@@ -31,6 +31,11 @@ import {
 class LogTool extends NotebookTools.Tool {
   methods: string[] = [];
 
+  protected onActiveNotebookPanelChanged(msg: Message): void {
+    super.onActiveNotebookPanelChanged(msg);
+    this.methods.push('onActiveNotebookPanelChanged');
+  }
+
   protected onActiveCellChanged(msg: Message): void {
     super.onActiveCellChanged(msg);
     this.methods.push('onActiveCellChanged');
@@ -47,6 +52,13 @@ class LogTool extends NotebookTools.Tool {
     super.onActiveCellMetadataChanged(msg);
     this.methods.push('onActiveCellMetadataChanged');
   }
+
+  protected onActiveNotebookPanelMetadataChanged(
+    msg: ObservableJSON.ChangeMessage
+  ): void {
+    super.onActiveNotebookPanelMetadataChanged(msg);
+    this.methods.push('onActiveNotebookPanelMetadataChanged');
+  }
 }
 
 class LogKeySelector extends NotebookTools.KeySelector {
@@ -99,12 +111,10 @@ describe('@jupyterlab/notebook', () => {
       await context0.initialize(true);
       panel0 = NBTestUtils.createNotebookPanel(context0);
       NBTestUtils.populateNotebook(panel0.content);
-
       const context1 = await createNotebookContext();
       await context1.initialize(true);
       panel1 = NBTestUtils.createNotebookPanel(context1);
       NBTestUtils.populateNotebook(panel1.content);
-
       tracker = new NotebookTracker({ namespace: 'notebook' });
       tracker.add(panel0);
       tracker.add(panel1);
@@ -131,6 +141,15 @@ describe('@jupyterlab/notebook', () => {
         });
       });
 
+      describe('#activeNotebookPanel', () => {
+        it('should be the active notebook', () => {
+          expect(notebookTools.activeNotebookPanel).to.equal(panel1);
+          tabpanel.currentIndex = 0;
+          simulate(panel0.node, 'focus');
+          expect(notebookTools.activeNotebookPanel).to.equal(panel0);
+        });
+      });
+
       describe('#activeCell', () => {
         it('should be the active cell', () => {
           expect(notebookTools.activeCell).to.equal(panel1.content.activeCell);
@@ -182,7 +201,17 @@ describe('@jupyterlab/notebook', () => {
         it('should be the notebooktools object used by the tool', () => {
           const tool = new NotebookTools.Tool({});
           notebookTools.addItem({ tool });
-          expect(tool.parent).to.equal(notebookTools);
+          expect(tool.notebookTools).to.equal(notebookTools);
+        });
+      });
+
+      describe('#onActiveNotebookPanelChanged()', () => {
+        it('should be called when the active notebook panel changes', () => {
+          const tool = new LogTool({});
+          notebookTools.addItem({ tool });
+          tool.methods = [];
+          simulate(panel0.node, 'focus');
+          expect(tool.methods).to.contain('onActiveNotebookPanelChanged');
         });
       });
 
@@ -208,7 +237,7 @@ describe('@jupyterlab/notebook', () => {
       });
 
       describe('#onActiveCellMetadataChanged()', () => {
-        it('should be called when the metadata changes', () => {
+        it('should be called when the active cell metadata changes', () => {
           const tool = new LogTool({});
           notebookTools.addItem({ tool });
           tool.methods = [];
@@ -218,6 +247,20 @@ describe('@jupyterlab/notebook', () => {
           expect(tool.methods).to.contain('onActiveCellMetadataChanged');
         });
       });
+
+      describe('#onActiveNotebookPanelMetadataChanged()', () => {
+        it('should be called when the active notebook panel metadata changes', () => {
+          const tool = new LogTool({});
+          notebookTools.addItem({ tool });
+          tool.methods = [];
+          const metadata = notebookTools.activeNotebookPanel.model.metadata;
+          metadata.set('foo', 1);
+          metadata.set('foo', 2);
+          expect(tool.methods).to.contain(
+            'onActiveNotebookPanelMetadataChanged'
+          );
+        });
+      });
     });
 
     describe('NotebookTools.ActiveCellTool', () => {
@@ -237,17 +280,21 @@ describe('@jupyterlab/notebook', () => {
       });
     });
 
-    describe('NotebookTools.MetadataEditorTool', () => {
+    describe('NotebookTools.CellMetadataEditorTool', () => {
       const editorServices = new CodeMirrorEditorFactory();
       const editorFactory = editorServices.newInlineEditor.bind(editorServices);
 
       it('should create a new metadata editor tool', () => {
-        const tool = new NotebookTools.MetadataEditorTool({ editorFactory });
-        expect(tool).to.be.an.instanceof(NotebookTools.MetadataEditorTool);
+        const tool = new NotebookTools.CellMetadataEditorTool({
+          editorFactory
+        });
+        expect(tool).to.be.an.instanceof(NotebookTools.CellMetadataEditorTool);
       });
 
       it('should handle a change to the active cell', () => {
-        const tool = new NotebookTools.MetadataEditorTool({ editorFactory });
+        const tool = new NotebookTools.CellMetadataEditorTool({
+          editorFactory
+        });
         notebookTools.addItem({ tool });
         const model = tool.editor.model;
         expect(JSON.stringify(model.value.text)).to.be.ok;
@@ -258,7 +305,9 @@ describe('@jupyterlab/notebook', () => {
       });
 
       it('should handle a change to the metadata', () => {
-        const tool = new NotebookTools.MetadataEditorTool({ editorFactory });
+        const tool = new NotebookTools.CellMetadataEditorTool({
+          editorFactory
+        });
         notebookTools.addItem({ tool });
         const model = tool.editor.model;
         const previous = model.value.text;
@@ -268,6 +317,51 @@ describe('@jupyterlab/notebook', () => {
       });
     });
 
+    describe('NotebookTools.NotebookMetadataEditorTool', () => {
+      const editorServices = new CodeMirrorEditorFactory();
+      const editorFactory = editorServices.newInlineEditor.bind(editorServices);
+
+      it('should create a new metadata editor tool', () => {
+        const tool = new NotebookTools.NotebookMetadataEditorTool({
+          editorFactory
+        });
+        expect(tool).to.be.an.instanceof(
+          NotebookTools.NotebookMetadataEditorTool
+        );
+      });
+
+      it('should handle a change to the active notebook', () => {
+        panel0.model.metadata.set('panel0', 1);
+        panel1.model.metadata.set('panel1', 1);
+        const tool = new NotebookTools.NotebookMetadataEditorTool({
+          editorFactory
+        });
+        notebookTools.addItem({ tool });
+        const model = tool.editor.model;
+        expect(JSON.stringify(model.value.text)).to.be.ok;
+
+        simulate(panel0.node, 'focus');
+        expect(JSON.stringify(model.value.text)).to.contain('panel0');
+        expect(JSON.stringify(model.value.text)).to.not.contain('panel1');
+
+        simulate(panel1.node, 'focus');
+        expect(JSON.stringify(model.value.text)).to.not.contain('panel0');
+        expect(JSON.stringify(model.value.text)).to.contain('panel1');
+      });
+
+      it('should handle a change to the metadata', () => {
+        const tool = new NotebookTools.NotebookMetadataEditorTool({
+          editorFactory
+        });
+        notebookTools.addItem({ tool });
+        const model = tool.editor.model;
+        const widget = tracker.currentWidget;
+        expect(JSON.stringify(model.value.text)).to.not.contain('newvalue');
+        widget.content.model.metadata.set('newvalue', 1);
+        expect(JSON.stringify(model.value.text)).to.contain('newvalue');
+      });
+    });
+
     describe('NotebookTools.KeySelector', () => {
       let tool: LogKeySelector;