Browse Source

modernize notebook

wip

wip

wip

modernize notebook tests

remove unused file

clean up
Steven Silvester 5 years ago
parent
commit
60b04db5d9

+ 11 - 0
packages/notebook/.vscode/launch.json

@@ -0,0 +1,11 @@
+{
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "type": "node",
+            "request": "attach",
+            "name": "Attach",
+            "port": 9229
+        }
+    ]
+}

+ 1 - 0
packages/notebook/babel.config.js

@@ -0,0 +1 @@
+module.exports = require('@jupyterlab/testutils/lib/babel.config');

+ 2 - 0
packages/notebook/jest.config.js

@@ -0,0 +1,2 @@
+const func = require('@jupyterlab/testutils/lib/jest-config-new');
+module.exports = func(__dirname);

+ 9 - 0
packages/notebook/package.json

@@ -29,9 +29,14 @@
   },
   "scripts": {
     "build": "tsc -b",
+    "build:test": "tsc --build tsconfig.test.json",
     "clean": "rimraf lib",
     "docs": "typedoc src",
     "prepublishOnly": "npm run build",
+    "test": "jest",
+    "test:cov": "jest --collect-coverage",
+    "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
+    "test:debug:watch": "node --inspect-brk node_modules/.bin/jest --runInBand --watch",
     "watch": "tsc -b --watch"
   },
   "dependencies": {
@@ -58,7 +63,11 @@
     "react": "~16.9.0"
   },
   "devDependencies": {
+    "@jupyterlab/testutils": "^2.1.0",
+    "@types/jest": "^24.0.23",
+    "jest": "^25.2.3",
     "rimraf": "~3.0.0",
+    "ts-jest": "^25.2.1",
     "typedoc": "^0.15.4",
     "typescript": "~3.7.3"
   },

File diff suppressed because it is too large
+ 190 - 173
packages/notebook/test/actions.spec.ts


+ 53 - 37
tests/test-notebook/src/default-toolbar.spec.ts → packages/notebook/test/default-toolbar.spec.ts

@@ -1,7 +1,6 @@
 // Copyright (c) Jupyter Development Team.
-// Distributed under the terms of the Modified BSD License.
 
-import { expect } from 'chai';
+import 'jest';
 
 import { simulate } from 'simulate-event';
 
@@ -18,19 +17,33 @@ import {
   NotebookActions,
   NotebookPanel,
   ToolbarItems
-} from '@jupyterlab/notebook';
+} from '../src';
 
 import {
   initNotebookContext,
   signalToPromise,
   sleep,
-  NBTestUtils,
   framePromise,
   acceptDialog
 } from '@jupyterlab/testutils';
 
+import { JupyterServer } from '@jupyterlab/testutils/lib/start_jupyter_server';
+
+import * as utils from './utils';
+
 const JUPYTER_CELL_MIME = 'application/vnd.jupyter.cells';
 
+const server = new JupyterServer();
+
+beforeAll(async () => {
+  jest.setTimeout(20000);
+  await server.start();
+});
+
+afterAll(async () => {
+  await server.shutdown();
+});
+
 describe('@jupyterlab/notebook', () => {
   describe('ToolbarItems', () => {
     describe('noKernel', () => {
@@ -39,8 +52,8 @@ describe('@jupyterlab/notebook', () => {
 
       beforeEach(async () => {
         context = await initNotebookContext();
-        panel = NBTestUtils.createNotebookPanel(context);
-        context.model.fromJSON(NBTestUtils.DEFAULT_CONTENT);
+        panel = utils.createNotebookPanel(context);
+        context.model.fromJSON(utils.DEFAULT_CONTENT);
       });
 
       afterEach(() => {
@@ -63,7 +76,9 @@ describe('@jupyterlab/notebook', () => {
           const button = ToolbarItems.createSaveButton(panel);
           Widget.attach(button, document.body);
           await framePromise();
-          expect(button.node.querySelector("[data-icon$='save']")).to.exist;
+          expect(
+            button.node.querySelector("[data-icon$='save']")
+          ).toBeDefined();
         });
       });
 
@@ -73,8 +88,8 @@ describe('@jupyterlab/notebook', () => {
           Widget.attach(button, document.body);
           await framePromise();
           simulate(button.node.firstChild as HTMLElement, 'mousedown');
-          expect(panel.content.activeCellIndex).to.equal(1);
-          expect(panel.content.activeCell).to.be.an.instanceof(CodeCell);
+          expect(panel.content.activeCellIndex).toBe(1);
+          expect(panel.content.activeCell).toBeInstanceOf(CodeCell);
           button.dispose();
         });
 
@@ -82,7 +97,7 @@ describe('@jupyterlab/notebook', () => {
           const button = ToolbarItems.createInsertButton(panel);
           Widget.attach(button, document.body);
           await framePromise();
-          expect(button.node.querySelector("[data-icon$='add']")).to.exist;
+          expect(button.node.querySelector("[data-icon$='add']")).toBeDefined();
           button.dispose();
         });
       });
@@ -94,10 +109,8 @@ describe('@jupyterlab/notebook', () => {
           Widget.attach(button, document.body);
           await framePromise();
           simulate(button.node.firstChild as HTMLElement, 'mousedown');
-          expect(panel.content.widgets.length).to.equal(count - 1);
-          expect(NBTestUtils.clipboard.hasData(JUPYTER_CELL_MIME)).to.equal(
-            true
-          );
+          expect(panel.content.widgets.length).toBe(count - 1);
+          expect(utils.clipboard.hasData(JUPYTER_CELL_MIME)).toBe(true);
           button.dispose();
         });
 
@@ -105,7 +118,7 @@ describe('@jupyterlab/notebook', () => {
           const button = ToolbarItems.createCutButton(panel);
           Widget.attach(button, document.body);
           await framePromise();
-          expect(button.node.querySelector("[data-icon$='cut']")).to.exist;
+          expect(button.node.querySelector("[data-icon$='cut']")).toBeDefined();
           button.dispose();
         });
       });
@@ -117,10 +130,8 @@ describe('@jupyterlab/notebook', () => {
           Widget.attach(button, document.body);
           await framePromise();
           simulate(button.node.firstChild as HTMLElement, 'mousedown');
-          expect(panel.content.widgets.length).to.equal(count);
-          expect(NBTestUtils.clipboard.hasData(JUPYTER_CELL_MIME)).to.equal(
-            true
-          );
+          expect(panel.content.widgets.length).toBe(count);
+          expect(utils.clipboard.hasData(JUPYTER_CELL_MIME)).toBe(true);
           button.dispose();
         });
 
@@ -128,7 +139,9 @@ describe('@jupyterlab/notebook', () => {
           const button = ToolbarItems.createCopyButton(panel);
           Widget.attach(button, document.body);
           await framePromise();
-          expect(button.node.querySelector("[data-icon$='copy']")).to.exist;
+          expect(
+            button.node.querySelector("[data-icon$='copy']")
+          ).toBeDefined();
           button.dispose();
         });
       });
@@ -142,7 +155,7 @@ describe('@jupyterlab/notebook', () => {
           NotebookActions.copy(panel.content);
           simulate(button.node.firstChild as HTMLElement, 'mousedown');
           await sleep();
-          expect(panel.content.widgets.length).to.equal(count + 1);
+          expect(panel.content.widgets.length).toBe(count + 1);
           button.dispose();
         });
 
@@ -150,7 +163,9 @@ describe('@jupyterlab/notebook', () => {
           const button = ToolbarItems.createPasteButton(panel);
           Widget.attach(button, document.body);
           await framePromise();
-          expect(button.node.querySelector("[data-icon$='paste']")).to.exist;
+          expect(
+            button.node.querySelector("[data-icon$='paste']")
+          ).toBeDefined();
           button.dispose();
         });
       });
@@ -163,10 +178,10 @@ describe('@jupyterlab/notebook', () => {
           const node = item.node.getElementsByTagName(
             'select'
           )[0] as HTMLSelectElement;
-          expect(node.value).to.equal('code');
+          expect(node.value).toBe('code');
           panel.content.activeCellIndex++;
           await framePromise();
-          expect(node.value).to.equal('markdown');
+          expect(node.value).toBe('markdown');
           item.dispose();
         });
 
@@ -177,10 +192,10 @@ describe('@jupyterlab/notebook', () => {
           const node = item.node.getElementsByTagName(
             'select'
           )[0] as HTMLSelectElement;
-          expect(node.value).to.equal('code');
+          expect(node.value).toBe('code');
           panel.content.select(panel.content.widgets[1]);
           await framePromise();
-          expect(node.value).to.equal('-');
+          expect(node.value).toBe('-');
           item.dispose();
         });
 
@@ -191,12 +206,12 @@ describe('@jupyterlab/notebook', () => {
           const node = item.node.getElementsByTagName(
             'select'
           )[0] as HTMLSelectElement;
-          expect(node.value).to.equal('code');
+          expect(node.value).toBe('code');
           const cell = panel.model!.contentFactory.createCodeCell({});
           panel.model!.cells.insert(1, cell);
           panel.content.select(panel.content.widgets[1]);
           await framePromise();
-          expect(node.value).to.equal('code');
+          expect(node.value).toBe('code');
           item.dispose();
         });
       });
@@ -208,7 +223,7 @@ describe('@jupyterlab/notebook', () => {
             item.widget.dispose();
             return name;
           });
-          expect(names).to.deep.equal([
+          expect(names).toEqual([
             'save',
             'insert',
             'cut',
@@ -233,8 +248,8 @@ describe('@jupyterlab/notebook', () => {
 
       beforeEach(async function() {
         context = await initNotebookContext({ startKernel: true });
-        panel = NBTestUtils.createNotebookPanel(context);
-        context.model.fromJSON(NBTestUtils.DEFAULT_CONTENT);
+        panel = utils.createNotebookPanel(context);
+        context.model.fromJSON(utils.DEFAULT_CONTENT);
       });
 
       afterEach(async () => {
@@ -261,8 +276,8 @@ describe('@jupyterlab/notebook', () => {
           context.sessionContext.statusChanged.connect((sender, status) => {
             // Find the right status idle message
             if (status === 'idle' && codeCell.model.outputs.length > 0) {
-              expect(mdCell.rendered).to.equal(true);
-              expect(widget.activeCellIndex).to.equal(2);
+              expect(mdCell.rendered).toBe(true);
+              expect(widget.activeCellIndex).toBe(2);
               button.dispose();
               p.resolve(0);
             }
@@ -276,7 +291,7 @@ describe('@jupyterlab/notebook', () => {
           const button = ToolbarItems.createRunButton(panel);
           Widget.attach(button, document.body);
           await framePromise();
-          expect(button.node.querySelector("[data-icon$='run']")).to.exist;
+          expect(button.node.querySelector("[data-icon$='run']")).toBeDefined();
         });
       });
 
@@ -301,7 +316,7 @@ describe('@jupyterlab/notebook', () => {
                   .filter(cell => cell.model.type === 'markdown')
                   .every(cell => (cell as MarkdownCell).rendered)
               );
-              expect(widget.activeCellIndex).to.equal(
+              expect(widget.activeCellIndex).toBe(
                 widget.widgets.filter(cell => cell.model.type === 'code').length
               );
               button.dispose();
@@ -318,8 +333,9 @@ describe('@jupyterlab/notebook', () => {
           const button = ToolbarItems.createRestartRunAllButton(panel);
           Widget.attach(button, document.body);
           await framePromise();
-          expect(button.node.querySelector("[data-icon$='fast-forward']")).to
-            .exist;
+          expect(
+            button.node.querySelector("[data-icon$='fast-forward']")
+          ).toBeDefined();
         });
       });
     });

+ 96 - 97
tests/test-notebook/src/model.spec.ts → packages/notebook/test/model.spec.ts

@@ -1,7 +1,6 @@
 // Copyright (c) Jupyter Development Team.
-// Distributed under the terms of the Modified BSD License.
 
-import { expect } from 'chai';
+import 'jest';
 
 import { ArrayExt, toArray } from '@lumino/algorithm';
 
@@ -9,18 +8,20 @@ import { CodeCellModel } from '@jupyterlab/cells';
 
 import * as nbformat from '@jupyterlab/nbformat';
 
-import { NotebookModel } from '@jupyterlab/notebook';
+import { NotebookModel } from '../src';
 
 import { ModelDB } from '@jupyterlab/observables';
 
-import { acceptDialog, NBTestUtils } from '@jupyterlab/testutils';
+import { acceptDialog } from '@jupyterlab/testutils';
+
+import * as utils from './utils';
 
 describe('@jupyterlab/notebook', () => {
   describe('NotebookModel', () => {
     describe('#constructor()', () => {
       it('should create a notebook model', () => {
         const model = new NotebookModel();
-        expect(model).to.be.an.instanceof(NotebookModel);
+        expect(model).toBeInstanceOf(NotebookModel);
       });
 
       it('should accept an optional language preference', () => {
@@ -28,13 +29,13 @@ describe('@jupyterlab/notebook', () => {
         const lang = model.metadata.get(
           'language_info'
         ) as nbformat.ILanguageInfoMetadata;
-        expect(lang.name).to.equal('python');
+        expect(lang.name).toBe('python');
       });
 
       it('should accept an optional factory', () => {
         const contentFactory = new NotebookModel.ContentFactory({});
         const model = new NotebookModel({ contentFactory });
-        expect(model.contentFactory.codeCellContentFactory).to.equal(
+        expect(model.contentFactory.codeCellContentFactory).toBe(
           contentFactory.codeCellContentFactory
         );
       });
@@ -45,14 +46,14 @@ describe('@jupyterlab/notebook', () => {
         const model = new NotebookModel();
         let called = false;
         model.metadata.changed.connect((sender, args) => {
-          expect(sender).to.equal(model.metadata);
-          expect(args.key).to.equal('foo');
-          expect(args.oldValue).to.be.undefined;
-          expect(args.newValue).to.equal(1);
+          expect(sender).toBe(model.metadata);
+          expect(args.key).toBe('foo');
+          expect(args.oldValue).toBeUndefined();
+          expect(args.newValue).toBe(1);
           called = true;
         });
         model.metadata.set('foo', 1);
-        expect(called).to.equal(true);
+        expect(called).toBe(true);
       });
 
       it('should not be emitted when the value does not change', () => {
@@ -63,7 +64,7 @@ describe('@jupyterlab/notebook', () => {
           called = true;
         });
         model.metadata.set('foo', 1);
-        expect(called).to.equal(false);
+        expect(called).toBe(false);
       });
     });
 
@@ -72,9 +73,9 @@ describe('@jupyterlab/notebook', () => {
         const model = new NotebookModel();
         const cell = model.contentFactory.createCodeCell({});
         model.cells.push(cell);
-        model.fromJSON(NBTestUtils.DEFAULT_CONTENT);
-        expect(ArrayExt.firstIndexOf(toArray(model.cells), cell)).to.equal(-1);
-        expect(model.cells.length).to.equal(6);
+        model.fromJSON(utils.DEFAULT_CONTENT);
+        expect(ArrayExt.firstIndexOf(toArray(model.cells), cell)).toBe(-1);
+        expect(model.cells.length).toBe(6);
       });
 
       it('should allow undoing a change', () => {
@@ -82,14 +83,14 @@ describe('@jupyterlab/notebook', () => {
         const cell = model.contentFactory.createCodeCell({});
         cell.value.text = 'foo';
         model.cells.push(cell);
-        model.fromJSON(NBTestUtils.DEFAULT_CONTENT);
+        model.fromJSON(utils.DEFAULT_CONTENT);
         model.cells.undo();
-        expect(model.cells.length).to.equal(1);
-        expect(model.cells.get(0).value.text).to.equal('foo');
-        expect(model.cells.get(0)).to.equal(cell); // should be ===.
+        expect(model.cells.length).toBe(1);
+        expect(model.cells.get(0).value.text).toBe('foo');
+        expect(model.cells.get(0)).toBe(cell); // should be ===.
       });
 
-      context('cells `changed` signal', () => {
+      describe('cells `changed` signal', () => {
         it('should emit a `contentChanged` signal upon cell addition', () => {
           const model = new NotebookModel();
           const cell = model.contentFactory.createCodeCell({});
@@ -98,7 +99,7 @@ describe('@jupyterlab/notebook', () => {
             called = true;
           });
           model.cells.push(cell);
-          expect(called).to.equal(true);
+          expect(called).toBe(true);
         });
 
         it('should emit a `contentChanged` signal upon cell removal', () => {
@@ -110,7 +111,7 @@ describe('@jupyterlab/notebook', () => {
             called = true;
           });
           model.cells.remove(0);
-          expect(called).to.equal(true);
+          expect(called).toBe(true);
         });
 
         it('should emit a `contentChanged` signal upon cell move', () => {
@@ -124,14 +125,14 @@ describe('@jupyterlab/notebook', () => {
             called = true;
           });
           model.cells.move(0, 1);
-          expect(called).to.equal(true);
+          expect(called).toBe(true);
         });
 
         it('should set the dirty flag', () => {
           const model = new NotebookModel();
           const cell = model.contentFactory.createCodeCell({});
           model.cells.push(cell);
-          expect(model.dirty).to.equal(true);
+          expect(model.dirty).toBe(true);
         });
       });
 
@@ -152,7 +153,7 @@ describe('@jupyterlab/notebook', () => {
             called = true;
           });
           model.metadata.set('foo', 'bar');
-          expect(called).to.equal(true);
+          expect(called).toBe(true);
         });
 
         it('should set the dirty flag', () => {
@@ -161,7 +162,7 @@ describe('@jupyterlab/notebook', () => {
           model.cells.push(cell);
           model.dirty = false;
           cell.value.text = 'foo';
-          expect(model.dirty).to.equal(true);
+          expect(model.dirty).toBe(true);
         });
       });
     });
@@ -169,7 +170,7 @@ describe('@jupyterlab/notebook', () => {
     describe('#contentFactory', () => {
       it('should be the cell model factory used by the model', () => {
         const model = new NotebookModel();
-        expect(model.contentFactory.codeCellContentFactory).to.equal(
+        expect(model.contentFactory.codeCellContentFactory).toBe(
           NotebookModel.defaultContentFactory.codeCellContentFactory
         );
       });
@@ -178,21 +179,21 @@ describe('@jupyterlab/notebook', () => {
     describe('#nbformat', () => {
       it('should get the major version number of the nbformat', () => {
         const model = new NotebookModel();
-        model.fromJSON(NBTestUtils.DEFAULT_CONTENT);
-        expect(model.nbformat).to.equal(NBTestUtils.DEFAULT_CONTENT.nbformat);
+        model.fromJSON(utils.DEFAULT_CONTENT);
+        expect(model.nbformat).toBe(utils.DEFAULT_CONTENT.nbformat);
       });
 
       it('should present a dialog when the format changes', () => {
         const model = new NotebookModel();
         const content = {
-          ...NBTestUtils.DEFAULT_CONTENT,
+          ...utils.DEFAULT_CONTENT,
           metadata: {
-            ...NBTestUtils.DEFAULT_CONTENT.metadata,
+            ...utils.DEFAULT_CONTENT.metadata,
             orig_nbformat: 1
           }
         };
         model.fromJSON(content);
-        expect(model.nbformat).to.equal(nbformat.MAJOR_VERSION);
+        expect(model.nbformat).toBe(nbformat.MAJOR_VERSION);
         return acceptDialog();
       });
     });
@@ -200,8 +201,8 @@ describe('@jupyterlab/notebook', () => {
     describe('#nbformatMinor', () => {
       it('should get the minor version number of the nbformat', () => {
         const model = new NotebookModel();
-        model.fromJSON(NBTestUtils.DEFAULT_CONTENT);
-        expect(model.nbformatMinor).to.equal(nbformat.MINOR_VERSION);
+        model.fromJSON(utils.DEFAULT_CONTENT);
+        expect(model.nbformatMinor).toBe(nbformat.MINOR_VERSION);
       });
     });
 
@@ -209,12 +210,12 @@ describe('@jupyterlab/notebook', () => {
       it('should get the default kernel name of the document', () => {
         const model = new NotebookModel();
         model.metadata.set('kernelspec', { name: 'python3' });
-        expect(model.defaultKernelName).to.equal('python3');
+        expect(model.defaultKernelName).toBe('python3');
       });
 
       it('should default to an empty string', () => {
         const model = new NotebookModel();
-        expect(model.defaultKernelName).to.equal('');
+        expect(model.defaultKernelName).toBe('');
       });
     });
 
@@ -222,85 +223,85 @@ describe('@jupyterlab/notebook', () => {
       it('should get the default kernel language of the document', () => {
         const model = new NotebookModel();
         model.metadata.set('language_info', { name: 'python' });
-        expect(model.defaultKernelLanguage).to.equal('python');
+        expect(model.defaultKernelLanguage).toBe('python');
       });
 
       it('should default to an empty string', () => {
         const model = new NotebookModel();
-        expect(model.defaultKernelLanguage).to.equal('');
+        expect(model.defaultKernelLanguage).toBe('');
       });
 
       it('should be set from the constructor arg', () => {
         const model = new NotebookModel({ languagePreference: 'foo' });
-        expect(model.defaultKernelLanguage).to.equal('foo');
+        expect(model.defaultKernelLanguage).toBe('foo');
       });
     });
 
     describe('#dispose()', () => {
       it('should dispose of the resources held by the model', () => {
         const model = new NotebookModel();
-        model.fromJSON(NBTestUtils.DEFAULT_CONTENT);
+        model.fromJSON(utils.DEFAULT_CONTENT);
         model.dispose();
-        expect(model.cells).to.be.null;
-        expect(model.isDisposed).to.equal(true);
+        expect(model.cells).toBeNull();
+        expect(model.isDisposed).toBe(true);
       });
 
       it('should be safe to call multiple times', () => {
         const model = new NotebookModel();
         model.dispose();
         model.dispose();
-        expect(model.isDisposed).to.equal(true);
+        expect(model.isDisposed).toBe(true);
       });
     });
 
     describe('#toString()', () => {
       it('should serialize the model to a string', () => {
         const model = new NotebookModel();
-        model.fromJSON(NBTestUtils.DEFAULT_CONTENT);
+        model.fromJSON(utils.DEFAULT_CONTENT);
         const text = model.toString();
         const data = JSON.parse(text);
-        expect(data.cells.length).to.equal(6);
+        expect(data.cells.length).toBe(6);
       });
     });
 
     describe('#fromString()', () => {
       it('should deserialize the model from a string', () => {
         const model = new NotebookModel();
-        model.fromString(JSON.stringify(NBTestUtils.DEFAULT_CONTENT));
-        expect(model.cells.length).to.equal(6);
+        model.fromString(JSON.stringify(utils.DEFAULT_CONTENT));
+        expect(model.cells.length).toBe(6);
       });
 
       it('should set the dirty flag', () => {
         const model = new NotebookModel();
         model.dirty = false;
-        model.fromString(JSON.stringify(NBTestUtils.DEFAULT_CONTENT));
-        expect(model.dirty).to.equal(true);
+        model.fromString(JSON.stringify(utils.DEFAULT_CONTENT));
+        expect(model.dirty).toBe(true);
       });
     });
 
     describe('#toJSON()', () => {
       it('should serialize the model to JSON', () => {
         const model = new NotebookModel();
-        model.fromJSON(NBTestUtils.DEFAULT_CONTENT);
+        model.fromJSON(utils.DEFAULT_CONTENT);
         const data = model.toJSON();
-        expect(data.cells.length).to.equal(6);
+        expect(data.cells.length).toBe(6);
       });
     });
 
     describe('#fromJSON()', () => {
       it('should serialize the model from JSON', () => {
         const model = new NotebookModel();
-        model.fromJSON(NBTestUtils.DEFAULT_CONTENT);
-        expect(model.cells.length).to.equal(6);
-        expect(model.nbformat).to.equal(NBTestUtils.DEFAULT_CONTENT.nbformat);
-        expect(model.nbformatMinor).to.equal(nbformat.MINOR_VERSION);
+        model.fromJSON(utils.DEFAULT_CONTENT);
+        expect(model.cells.length).toBe(6);
+        expect(model.nbformat).toBe(utils.DEFAULT_CONTENT.nbformat);
+        expect(model.nbformatMinor).toBe(nbformat.MINOR_VERSION);
       });
 
       it('should set the dirty flag', () => {
         const model = new NotebookModel();
         model.dirty = false;
-        model.fromJSON(NBTestUtils.DEFAULT_CONTENT);
-        expect(model.dirty).to.equal(true);
+        model.fromJSON(utils.DEFAULT_CONTENT);
+        expect(model.dirty).toBe(true);
       });
     });
 
@@ -310,14 +311,14 @@ describe('@jupyterlab/notebook', () => {
         const metadata = model.metadata;
         expect(metadata.has('kernelspec'));
         expect(metadata.has('language_info'));
-        expect(metadata.size).to.equal(2);
+        expect(metadata.size).toBe(2);
       });
 
       it('should set the dirty flag when changed', () => {
         const model = new NotebookModel();
-        expect(model.dirty).to.equal(false);
+        expect(model.dirty).toBe(false);
         model.metadata.set('foo', 'bar');
-        expect(model.dirty).to.equal(true);
+        expect(model.dirty).toBe(true);
       });
 
       it('should emit the `contentChanged` signal', () => {
@@ -327,31 +328,31 @@ describe('@jupyterlab/notebook', () => {
           called = true;
         });
         model.metadata.set('foo', 'bar');
-        expect(called).to.equal(true);
+        expect(called).toBe(true);
       });
 
       it('should emit the `metadataChanged` signal', () => {
         const model = new NotebookModel();
         let called = false;
         model.metadata.changed.connect((sender, args) => {
-          expect(sender).to.equal(model.metadata);
-          expect(args.key).to.equal('foo');
-          expect(args.oldValue).to.be.undefined;
-          expect(args.newValue).to.equal('bar');
+          expect(sender).toBe(model.metadata);
+          expect(args.key).toBe('foo');
+          expect(args.oldValue).toBeUndefined();
+          expect(args.newValue).toBe('bar');
           called = true;
         });
         model.metadata.set('foo', 'bar');
-        expect(called).to.equal(true);
+        expect(called).toBe(true);
       });
     });
 
     describe('#initialize()', () => {
       it('should add one code cell if the model is empty', () => {
         const model = new NotebookModel();
-        expect(model.cells.length).to.equal(0);
+        expect(model.cells.length).toBe(0);
         model.initialize();
-        expect(model.cells.length).to.equal(1);
-        expect(model.cells.get(0).type).to.equal('code');
+        expect(model.cells.length).toBe(1);
+        expect(model.cells.get(0).type).toBe('code');
       });
 
       it('should clear undo state', () => {
@@ -359,18 +360,18 @@ describe('@jupyterlab/notebook', () => {
         const cell = model.contentFactory.createCodeCell({});
         cell.value.text = 'foo';
         model.cells.push(cell);
-        expect(model.cells.canUndo).to.equal(true);
+        expect(model.cells.canUndo).toBe(true);
         model.initialize();
-        expect(model.cells.canUndo).to.equal(false);
+        expect(model.cells.canUndo).toBe(false);
       });
     });
 
     describe('.ContentFactory', () => {
       let factory = new NotebookModel.ContentFactory({});
 
-      context('#codeCellContentFactory', () => {
+      describe('#codeCellContentFactory', () => {
         it('should be a code cell content factory', () => {
-          expect(factory.codeCellContentFactory).to.equal(
+          expect(factory.codeCellContentFactory).toBe(
             CodeCellModel.defaultContentFactory
           );
         });
@@ -380,33 +381,31 @@ describe('@jupyterlab/notebook', () => {
           factory = new NotebookModel.ContentFactory({
             codeCellContentFactory
           });
-          expect(factory.codeCellContentFactory).to.equal(
-            codeCellContentFactory
-          );
+          expect(factory.codeCellContentFactory).toBe(codeCellContentFactory);
         });
       });
 
-      context('#createCell()', () => {
+      describe('#createCell()', () => {
         it('should create a new code cell', () => {
           const cell = factory.createCell('code', {});
-          expect(cell.type).to.equal('code');
+          expect(cell.type).toBe('code');
         });
 
         it('should create a new code cell', () => {
           const cell = factory.createCell('markdown', {});
-          expect(cell.type).to.equal('markdown');
+          expect(cell.type).toBe('markdown');
         });
 
         it('should create a new code cell', () => {
           const cell = factory.createCell('raw', {});
-          expect(cell.type).to.equal('raw');
+          expect(cell.type).toBe('raw');
         });
       });
 
-      context('#createCodeCell()', () => {
+      describe('#createCodeCell()', () => {
         it('should create a new code cell', () => {
           const cell = factory.createCodeCell({});
-          expect(cell.type).to.equal('code');
+          expect(cell.type).toBe('code');
         });
 
         it('should clone an existing code cell', () => {
@@ -414,7 +413,7 @@ describe('@jupyterlab/notebook', () => {
           orig.value.text = 'foo';
           const cell = orig.toJSON();
           const newCell = factory.createCodeCell({ cell });
-          expect(newCell.value.text).to.equal('foo');
+          expect(newCell.value.text).toBe('foo');
         });
 
         it('should clone an existing raw cell', () => {
@@ -422,14 +421,14 @@ describe('@jupyterlab/notebook', () => {
           orig.value.text = 'foo';
           const cell = orig.toJSON();
           const newCell = factory.createCodeCell({ cell });
-          expect(newCell.value.text).to.equal('foo');
+          expect(newCell.value.text).toBe('foo');
         });
       });
 
-      context('#createRawCell()', () => {
+      describe('#createRawCell()', () => {
         it('should create a new raw cell', () => {
           const cell = factory.createRawCell({});
-          expect(cell.type).to.equal('raw');
+          expect(cell.type).toBe('raw');
         });
 
         it('should clone an existing raw cell', () => {
@@ -437,7 +436,7 @@ describe('@jupyterlab/notebook', () => {
           orig.value.text = 'foo';
           const cell = orig.toJSON();
           const newCell = factory.createRawCell({ cell });
-          expect(newCell.value.text).to.equal('foo');
+          expect(newCell.value.text).toBe('foo');
         });
 
         it('should clone an existing code cell', () => {
@@ -445,14 +444,14 @@ describe('@jupyterlab/notebook', () => {
           orig.value.text = 'foo';
           const cell = orig.toJSON();
           const newCell = factory.createRawCell({ cell });
-          expect(newCell.value.text).to.equal('foo');
+          expect(newCell.value.text).toBe('foo');
         });
       });
 
       describe('#createMarkdownCell()', () => {
         it('should create a new markdown cell', () => {
           const cell = factory.createMarkdownCell({});
-          expect(cell.type).to.equal('markdown');
+          expect(cell.type).toBe('markdown');
         });
 
         it('should clone an existing markdown cell', () => {
@@ -460,7 +459,7 @@ describe('@jupyterlab/notebook', () => {
           orig.value.text = 'foo';
           const cell = orig.toJSON();
           const newCell = factory.createMarkdownCell({ cell });
-          expect(newCell.value.text).to.equal('foo');
+          expect(newCell.value.text).toBe('foo');
         });
 
         it('should clone an existing raw cell', () => {
@@ -468,13 +467,13 @@ describe('@jupyterlab/notebook', () => {
           orig.value.text = 'foo';
           const cell = orig.toJSON();
           const newCell = factory.createMarkdownCell({ cell });
-          expect(newCell.value.text).to.equal('foo');
+          expect(newCell.value.text).toBe('foo');
         });
       });
 
       describe('#modelDB', () => {
         it('should be undefined by default', () => {
-          expect(factory.modelDB).to.be.undefined;
+          expect(factory.modelDB).toBeUndefined();
         });
       });
 
@@ -482,11 +481,11 @@ describe('@jupyterlab/notebook', () => {
         it('should create a new content factory with a new IModelDB', () => {
           const modelDB = new ModelDB();
           const factory = new NotebookModel.ContentFactory({ modelDB });
-          expect(factory.modelDB).to.equal(modelDB);
+          expect(factory.modelDB).toBe(modelDB);
           const newModelDB = new ModelDB();
           const newFactory = factory.clone(newModelDB);
-          expect(newFactory.modelDB).to.equal(newModelDB);
-          expect(newFactory.codeCellContentFactory).to.equal(
+          expect(newFactory.modelDB).toBe(newModelDB);
+          expect(newFactory.codeCellContentFactory).toBe(
             factory.codeCellContentFactory
           );
         });
@@ -495,7 +494,7 @@ describe('@jupyterlab/notebook', () => {
 
     describe('.defaultContentFactory', () => {
       it('should be a ContentFactory', () => {
-        expect(NotebookModel.defaultContentFactory).to.be.an.instanceof(
+        expect(NotebookModel.defaultContentFactory).toBeInstanceOf(
           NotebookModel.ContentFactory
         );
       });

+ 18 - 19
tests/test-notebook/src/modelfactory.spec.ts → packages/notebook/test/modelfactory.spec.ts

@@ -1,26 +1,25 @@
 // Copyright (c) Jupyter Development Team.
-// Distributed under the terms of the Modified BSD License.
 
-import { expect } from 'chai';
+import 'jest';
 
 import { CodeCellModel } from '@jupyterlab/cells';
 
-import { NotebookModel } from '@jupyterlab/notebook';
+import { NotebookModel } from '../src';
 
-import { NotebookModelFactory } from '@jupyterlab/notebook';
+import { NotebookModelFactory } from '../src';
 
 describe('@jupyterlab/notebook', () => {
   describe('NotebookModelFactory', () => {
     describe('#constructor', () => {
       it('should create a new notebook model factory', () => {
         const factory = new NotebookModelFactory({});
-        expect(factory).to.be.an.instanceof(NotebookModelFactory);
+        expect(factory).toBeInstanceOf(NotebookModelFactory);
       });
 
       it('should accept a code cell content factory', () => {
         const codeCellContentFactory = new CodeCellModel.ContentFactory();
         const factory = new NotebookModelFactory({ codeCellContentFactory });
-        expect(factory.contentFactory.codeCellContentFactory).to.equal(
+        expect(factory.contentFactory.codeCellContentFactory).toBe(
           codeCellContentFactory
         );
       });
@@ -28,14 +27,14 @@ describe('@jupyterlab/notebook', () => {
       it('should accept a notebook model content factory', () => {
         const contentFactory = new NotebookModel.ContentFactory({});
         const factory = new NotebookModelFactory({ contentFactory });
-        expect(factory.contentFactory).to.equal(contentFactory);
+        expect(factory.contentFactory).toBe(contentFactory);
       });
     });
 
     describe('#contentFactory', () => {
       it('should be the content factory used by the model factory', () => {
         const factory = new NotebookModelFactory({});
-        expect(factory.contentFactory).to.be.an.instanceof(
+        expect(factory.contentFactory).toBeInstanceOf(
           NotebookModel.ContentFactory
         );
       });
@@ -44,30 +43,30 @@ describe('@jupyterlab/notebook', () => {
     describe('#name', () => {
       it('should get the name of the model factory', () => {
         const factory = new NotebookModelFactory({});
-        expect(factory.name).to.equal('notebook');
+        expect(factory.name).toBe('notebook');
       });
     });
 
     describe('#contentType', () => {
       it('should get the file type', () => {
         const factory = new NotebookModelFactory({});
-        expect(factory.contentType).to.equal('notebook');
+        expect(factory.contentType).toBe('notebook');
       });
     });
 
     describe('#fileFormat', () => {
       it('should get the file format', () => {
         const factory = new NotebookModelFactory({});
-        expect(factory.fileFormat).to.equal('json');
+        expect(factory.fileFormat).toBe('json');
       });
     });
 
     describe('#isDisposed', () => {
       it('should get whether the factory is disposed', () => {
         const factory = new NotebookModelFactory({});
-        expect(factory.isDisposed).to.equal(false);
+        expect(factory.isDisposed).toBe(false);
         factory.dispose();
-        expect(factory.isDisposed).to.equal(true);
+        expect(factory.isDisposed).toBe(true);
       });
     });
 
@@ -75,14 +74,14 @@ describe('@jupyterlab/notebook', () => {
       it('should dispose of the model factory', () => {
         const factory = new NotebookModelFactory({});
         factory.dispose();
-        expect(factory.isDisposed).to.equal(true);
+        expect(factory.isDisposed).toBe(true);
       });
 
       it('should be safe to call multiple times', () => {
         const factory = new NotebookModelFactory({});
         factory.dispose();
         factory.dispose();
-        expect(factory.isDisposed).to.equal(true);
+        expect(factory.isDisposed).toBe(true);
       });
     });
 
@@ -90,21 +89,21 @@ describe('@jupyterlab/notebook', () => {
       it('should create a new model for a given path', () => {
         const factory = new NotebookModelFactory({});
         const model = factory.createNew();
-        expect(model).to.be.an.instanceof(NotebookModel);
+        expect(model).toBeInstanceOf(NotebookModel);
       });
 
       it('should accept a language preference', () => {
         const factory = new NotebookModelFactory({});
         const model = factory.createNew('foo');
-        expect(model.defaultKernelLanguage).to.equal('foo');
+        expect(model.defaultKernelLanguage).toBe('foo');
       });
     });
 
     describe('#preferredLanguage()', () => {
       it('should always return an empty string', () => {
         const factory = new NotebookModelFactory({});
-        expect(factory.preferredLanguage('')).to.equal('');
-        expect(factory.preferredLanguage('.ipynb')).to.equal('');
+        expect(factory.preferredLanguage('')).toBe('');
+        expect(factory.preferredLanguage('.ipynb')).toBe('');
       });
     });
   });

+ 83 - 73
tests/test-notebook/src/notebooktools.spec.ts → packages/notebook/test/notebooktools.spec.ts

@@ -1,7 +1,6 @@
 // Copyright (c) Jupyter Development Team.
-// Distributed under the terms of the Modified BSD License.
 
-import { expect } from 'chai';
+import 'jest';
 
 import { Message } from '@lumino/messaging';
 
@@ -23,9 +22,11 @@ import {
   NotebookPanel,
   NotebookTools,
   NotebookTracker
-} from '@jupyterlab/notebook';
+} from '../src';
 
-import { initNotebookContext, sleep, NBTestUtils } from '@jupyterlab/testutils';
+import { initNotebookContext, sleep } from '@jupyterlab/testutils';
+import { JupyterServer } from '@jupyterlab/testutils/lib/start_jupyter_server';
+import * as utils from './utils';
 
 class LogTool extends NotebookTools.Tool {
   methods: string[] = [];
@@ -97,6 +98,17 @@ class LogKeySelector extends NotebookTools.KeySelector {
   }
 }
 
+const server = new JupyterServer();
+
+beforeAll(async () => {
+  jest.setTimeout(20000);
+  await server.start();
+});
+
+afterAll(async () => {
+  await server.shutdown();
+});
+
 describe('@jupyterlab/notebook', () => {
   describe('notebooktools', () => {
     let notebookTools: NotebookTools;
@@ -109,11 +121,11 @@ describe('@jupyterlab/notebook', () => {
 
     beforeEach(async () => {
       context0 = await initNotebookContext();
-      panel0 = NBTestUtils.createNotebookPanel(context0);
-      NBTestUtils.populateNotebook(panel0.content);
+      panel0 = utils.createNotebookPanel(context0);
+      utils.populateNotebook(panel0.content);
       context1 = await initNotebookContext();
-      panel1 = NBTestUtils.createNotebookPanel(context1);
-      NBTestUtils.populateNotebook(panel1.content);
+      panel1 = utils.createNotebookPanel(context1);
+      utils.populateNotebook(panel1.content);
       tracker = new NotebookTracker({ namespace: 'notebook' });
       await tracker.add(panel0);
       await tracker.add(panel1);
@@ -141,40 +153,40 @@ describe('@jupyterlab/notebook', () => {
     describe('NotebookTools', () => {
       describe('#constructor()', () => {
         it('should create a notebooktools object', () => {
-          expect(notebookTools).to.be.an.instanceof(NotebookTools);
+          expect(notebookTools).toBeInstanceOf(NotebookTools);
         });
       });
 
       describe('#activeNotebookPanel', () => {
         it('should be the active notebook', () => {
-          expect(notebookTools.activeNotebookPanel).to.equal(panel1);
+          expect(notebookTools.activeNotebookPanel).toBe(panel1);
           tabpanel.currentIndex = 0;
           simulate(panel0.node, 'focus');
-          expect(notebookTools.activeNotebookPanel).to.equal(panel0);
+          expect(notebookTools.activeNotebookPanel).toBe(panel0);
         });
       });
 
       describe('#activeCell', () => {
         it('should be the active cell', () => {
-          expect(notebookTools.activeCell).to.equal(panel1.content.activeCell);
+          expect(notebookTools.activeCell).toBe(panel1.content.activeCell);
           tabpanel.currentIndex = 0;
           simulate(panel0.node, 'focus');
-          expect(notebookTools.activeCell).to.equal(panel0.content.activeCell);
+          expect(notebookTools.activeCell).toBe(panel0.content.activeCell);
         });
       });
 
       describe('#selectedCells', () => {
         it('should be the currently selected cells', () => {
-          expect(notebookTools.selectedCells).to.deep.equal([
+          expect(notebookTools.selectedCells).toEqual([
             panel1.content.activeCell
           ]);
           tabpanel.currentIndex = 0;
           simulate(panel0.node, 'focus');
-          expect(notebookTools.selectedCells).to.deep.equal([
+          expect(notebookTools.selectedCells).toEqual([
             panel0.content.activeCell
           ]);
           panel0.content.select(panel0.content.widgets[1]);
-          expect(notebookTools.selectedCells.length).to.equal(2);
+          expect(notebookTools.selectedCells.length).toBe(2);
         });
       });
 
@@ -197,7 +209,7 @@ describe('@jupyterlab/notebook', () => {
       describe('#constructor', () => {
         it('should create a new base tool', () => {
           const tool = new NotebookTools.Tool();
-          expect(tool).to.be.an.instanceof(NotebookTools.Tool);
+          expect(tool).toBeInstanceOf(NotebookTools.Tool);
         });
       });
 
@@ -205,7 +217,7 @@ describe('@jupyterlab/notebook', () => {
         it('should be the notebooktools object used by the tool', () => {
           const tool = new NotebookTools.Tool({});
           notebookTools.addItem({ tool });
-          expect(tool.notebookTools).to.equal(notebookTools);
+          expect(tool.notebookTools).toBe(notebookTools);
         });
       });
 
@@ -215,7 +227,7 @@ describe('@jupyterlab/notebook', () => {
           notebookTools.addItem({ tool });
           tool.methods = [];
           simulate(panel0.node, 'focus');
-          expect(tool.methods).to.contain('onActiveNotebookPanelChanged');
+          expect(tool.methods).toContain('onActiveNotebookPanelChanged');
         });
       });
 
@@ -225,7 +237,7 @@ describe('@jupyterlab/notebook', () => {
           notebookTools.addItem({ tool });
           tool.methods = [];
           simulate(panel0.node, 'focus');
-          expect(tool.methods).to.contain('onActiveCellChanged');
+          expect(tool.methods).toContain('onActiveCellChanged');
         });
       });
 
@@ -236,7 +248,7 @@ describe('@jupyterlab/notebook', () => {
           tool.methods = [];
           const current = tracker.currentWidget!;
           current.content.select(current.content.widgets[1]);
-          expect(tool.methods).to.contain('onSelectionChanged');
+          expect(tool.methods).toContain('onSelectionChanged');
         });
       });
 
@@ -248,7 +260,7 @@ describe('@jupyterlab/notebook', () => {
           const metadata = notebookTools.activeCell!.model.metadata;
           metadata.set('foo', 1);
           metadata.set('foo', 2);
-          expect(tool.methods).to.contain('onActiveCellMetadataChanged');
+          expect(tool.methods).toContain('onActiveCellMetadataChanged');
         });
       });
 
@@ -260,7 +272,7 @@ describe('@jupyterlab/notebook', () => {
           const metadata = notebookTools.activeNotebookPanel!.model!.metadata;
           metadata.set('foo', 1);
           metadata.set('foo', 2);
-          expect(tool.methods).to.contain(
+          expect(tool.methods).toContain(
             'onActiveNotebookPanelMetadataChanged'
           );
         });
@@ -271,7 +283,7 @@ describe('@jupyterlab/notebook', () => {
       it('should create a new active cell tool', () => {
         const tool = new NotebookTools.ActiveCellTool();
         notebookTools.addItem({ tool });
-        expect(tool).to.be.an.instanceof(NotebookTools.ActiveCellTool);
+        expect(tool).toBeInstanceOf(NotebookTools.ActiveCellTool);
       });
 
       it('should handle a change to the active cell', () => {
@@ -280,7 +292,7 @@ describe('@jupyterlab/notebook', () => {
         const widget = tracker.currentWidget!;
         widget.content.activeCellIndex++;
         widget.content.activeCell!.model.metadata.set('bar', 1);
-        expect(tool.node.querySelector('.jp-InputArea-editor')).to.be.ok;
+        expect(tool.node.querySelector('.jp-InputArea-editor')).toBeTruthy();
       });
     });
 
@@ -292,7 +304,7 @@ describe('@jupyterlab/notebook', () => {
         const tool = new NotebookTools.CellMetadataEditorTool({
           editorFactory
         });
-        expect(tool).to.be.an.instanceof(NotebookTools.CellMetadataEditorTool);
+        expect(tool).toBeInstanceOf(NotebookTools.CellMetadataEditorTool);
       });
 
       it('should handle a change to the active cell', () => {
@@ -301,11 +313,11 @@ describe('@jupyterlab/notebook', () => {
         });
         notebookTools.addItem({ tool });
         const model = tool.editor.model;
-        expect(JSON.stringify(model.value.text)).to.be.ok;
+        expect(JSON.stringify(model.value.text)).toBeTruthy();
         const widget = tracker.currentWidget!;
         widget.content.activeCellIndex++;
         widget.content.activeCell!.model.metadata.set('bar', 1);
-        expect(JSON.stringify(model.value.text)).to.contain('bar');
+        expect(JSON.stringify(model.value.text)).toContain('bar');
       });
 
       it('should handle a change to the metadata', () => {
@@ -317,7 +329,7 @@ describe('@jupyterlab/notebook', () => {
         const previous = model.value.text;
         const metadata = notebookTools.activeCell!.model.metadata;
         metadata.set('foo', 1);
-        expect(model.value.text).to.not.equal(previous);
+        expect(model.value.text).not.toBe(previous);
       });
     });
 
@@ -329,9 +341,7 @@ describe('@jupyterlab/notebook', () => {
         const tool = new NotebookTools.NotebookMetadataEditorTool({
           editorFactory
         });
-        expect(tool).to.be.an.instanceof(
-          NotebookTools.NotebookMetadataEditorTool
-        );
+        expect(tool).toBeInstanceOf(NotebookTools.NotebookMetadataEditorTool);
       });
 
       it('should handle a change to the active notebook', () => {
@@ -342,15 +352,15 @@ describe('@jupyterlab/notebook', () => {
         });
         notebookTools.addItem({ tool });
         const model = tool.editor.model;
-        expect(JSON.stringify(model.value.text)).to.be.ok;
+        expect(JSON.stringify(model.value.text)).toBeTruthy();
 
         simulate(panel0.node, 'focus');
-        expect(JSON.stringify(model.value.text)).to.contain('panel0');
-        expect(JSON.stringify(model.value.text)).to.not.contain('panel1');
+        expect(JSON.stringify(model.value.text)).toContain('panel0');
+        expect(JSON.stringify(model.value.text)).not.toContain('panel1');
 
         simulate(panel1.node, 'focus');
-        expect(JSON.stringify(model.value.text)).to.not.contain('panel0');
-        expect(JSON.stringify(model.value.text)).to.contain('panel1');
+        expect(JSON.stringify(model.value.text)).not.toContain('panel0');
+        expect(JSON.stringify(model.value.text)).toContain('panel1');
       });
 
       it('should handle a change to the metadata', () => {
@@ -360,9 +370,9 @@ describe('@jupyterlab/notebook', () => {
         notebookTools.addItem({ tool });
         const model = tool.editor.model;
         const widget = tracker.currentWidget!;
-        expect(JSON.stringify(model.value.text)).to.not.contain('newvalue');
+        expect(JSON.stringify(model.value.text)).not.toContain('newvalue');
         widget.content.model!.metadata.set('newvalue', 1);
-        expect(JSON.stringify(model.value.text)).to.contain('newvalue');
+        expect(JSON.stringify(model.value.text)).toContain('newvalue');
       });
     });
 
@@ -388,51 +398,51 @@ describe('@jupyterlab/notebook', () => {
 
       describe('#constructor()', () => {
         it('should create a new key selector', () => {
-          expect(tool).to.be.an.instanceof(NotebookTools.KeySelector);
+          expect(tool).toBeInstanceOf(NotebookTools.KeySelector);
         });
       });
 
       describe('#key', () => {
         it('should be the key used by the selector', () => {
-          expect(tool.key).to.equal('foo');
+          expect(tool.key).toBe('foo');
         });
       });
 
       describe('#selectNode', () => {
         it('should be the select node', () => {
-          expect(tool.selectNode.localName).to.equal('select');
+          expect(tool.selectNode.localName).toBe('select');
         });
       });
 
       describe('#handleEvent()', () => {
-        context('change', () => {
+        describe('change', () => {
           it('should update the metadata', () => {
             const select = tool.selectNode;
             simulate(select, 'focus');
             select.selectedIndex = 1;
             simulate(select, 'change');
-            expect(tool.events).to.contain('change');
+            expect(tool.events).toContain('change');
             const metadata = notebookTools.activeCell!.model.metadata;
-            expect(metadata.get('foo')).to.deep.equal([1, 2, 'a']);
+            expect(metadata.get('foo')).toEqual([1, 2, 'a']);
           });
         });
 
-        context('focus', () => {
+        describe('focus', () => {
           it('should add the focused class to the wrapper node', () => {
             const select = tool.selectNode;
             simulate(select, 'focus');
             const selector = '.jp-mod-focused';
-            expect(tool.node.querySelector(selector)).to.be.ok;
+            expect(tool.node.querySelector(selector)).toBeTruthy();
           });
         });
 
-        context('blur', () => {
+        describe('blur', () => {
           it('should remove the focused class from the wrapper node', () => {
             const select = tool.selectNode;
             simulate(select, 'focus');
             simulate(select, 'blur');
             const selector = '.jp-mod-focused';
-            expect(tool.node.querySelector(selector)).to.not.be.ok;
+            expect(tool.node.querySelector(selector)).toBeFalsy();
           });
         });
       });
@@ -440,12 +450,12 @@ describe('@jupyterlab/notebook', () => {
       describe('#onAfterAttach()', () => {
         it('should add event listeners', () => {
           const select = tool.selectNode;
-          expect(tool.methods).to.contain('onAfterAttach');
+          expect(tool.methods).toContain('onAfterAttach');
           simulate(select, 'focus');
           simulate(select, 'blur');
           select.selectedIndex = 0;
           simulate(select, 'change');
-          expect(tool.events).to.deep.equal(['change']);
+          expect(tool.events).toEqual(['change']);
         });
       });
 
@@ -453,11 +463,11 @@ describe('@jupyterlab/notebook', () => {
         it('should remove event listeners', () => {
           const select = tool.selectNode;
           notebookTools.dispose();
-          expect(tool.methods).to.contain('onBeforeDetach');
+          expect(tool.methods).toContain('onBeforeDetach');
           simulate(select, 'focus');
           simulate(select, 'blur');
           simulate(select, 'change');
-          expect(tool.events).to.deep.equal([]);
+          expect(tool.events).toEqual([]);
         });
       });
 
@@ -467,9 +477,9 @@ describe('@jupyterlab/notebook', () => {
           simulate(select, 'focus');
           select.selectedIndex = 1;
           simulate(select, 'change');
-          expect(tool.methods).to.contain('onValueChanged');
+          expect(tool.methods).toContain('onValueChanged');
           const metadata = notebookTools.activeCell!.model.metadata;
-          expect(metadata.get('foo')).to.deep.equal([1, 2, 'a']);
+          expect(metadata.get('foo')).toEqual([1, 2, 'a']);
         });
       });
 
@@ -478,8 +488,8 @@ describe('@jupyterlab/notebook', () => {
           const cell = panel0.content.model!.cells.get(1);
           cell.metadata.set('foo', 1);
           panel0.content.activeCellIndex = 1;
-          expect(tool.methods).to.contain('onActiveCellChanged');
-          expect(tool.selectNode.value).to.equal('1');
+          expect(tool.methods).toContain('onActiveCellChanged');
+          expect(tool.selectNode.value).toBe('1');
         });
       });
 
@@ -487,8 +497,8 @@ describe('@jupyterlab/notebook', () => {
         it('should update the select value', () => {
           const metadata = notebookTools.activeCell!.model.metadata;
           metadata.set('foo', 1);
-          expect(tool.methods).to.contain('onActiveCellMetadataChanged');
-          expect(tool.selectNode.value).to.equal('1');
+          expect(tool.methods).toContain('onActiveCellMetadataChanged');
+          expect(tool.selectNode.value).toBe('1');
         });
       });
     });
@@ -500,16 +510,16 @@ describe('@jupyterlab/notebook', () => {
         notebookTools.addItem({ tool });
         simulate(panel0.node, 'focus');
         tabpanel.currentIndex = 2;
-        expect(tool).to.be.an.instanceof(NotebookTools.KeySelector);
-        expect(tool.key).to.equal('slideshow');
+        expect(tool).toBeInstanceOf(NotebookTools.KeySelector);
+        expect(tool.key).toBe('slideshow');
         const select = tool.selectNode;
-        expect(select.value).to.equal('');
+        expect(select.value).toBe('');
         const metadata = notebookTools.activeCell!.model.metadata;
-        expect(metadata.get('slideshow')).to.be.undefined;
+        expect(metadata.get('slideshow')).toBeUndefined();
         simulate(select, 'focus');
         tool.selectNode.selectedIndex = 1;
         simulate(select, 'change');
-        expect(metadata.get('slideshow')).to.deep.equal({
+        expect(metadata.get('slideshow')).toEqual({
           slide_type: 'slide'
         });
       });
@@ -532,17 +542,17 @@ describe('@jupyterlab/notebook', () => {
         simulate(panel0.node, 'focus');
         NotebookActions.changeCellType(panel0.content, 'raw');
         tabpanel.currentIndex = 2;
-        expect(tool).to.be.an.instanceof(NotebookTools.KeySelector);
-        expect(tool.key).to.equal('raw_mimetype');
+        expect(tool).toBeInstanceOf(NotebookTools.KeySelector);
+        expect(tool.key).toBe('raw_mimetype');
         const select = tool.selectNode;
-        expect(select.value).to.equal('');
+        expect(select.value).toBe('');
 
         const metadata = notebookTools.activeCell!.model.metadata;
-        expect(metadata.get('raw_mimetype')).to.be.undefined;
+        expect(metadata.get('raw_mimetype')).toBeUndefined();
         simulate(select, 'focus');
         tool.selectNode.selectedIndex = 2;
         simulate(select, 'change');
-        expect(metadata.get('raw_mimetype')).to.equal('text/restructuredtext');
+        expect(metadata.get('raw_mimetype')).toBe('text/restructuredtext');
       });
 
       it('should have no effect on a code cell', () => {
@@ -561,11 +571,11 @@ describe('@jupyterlab/notebook', () => {
         NotebookActions.changeCellType(panel0.content, 'code');
 
         tabpanel.currentIndex = 2;
-        expect(tool).to.be.an.instanceof(NotebookTools.KeySelector);
-        expect(tool.key).to.equal('raw_mimetype');
+        expect(tool).toBeInstanceOf(NotebookTools.KeySelector);
+        expect(tool.key).toBe('raw_mimetype');
         const select = tool.selectNode;
-        expect(select.disabled).to.equal(true);
-        expect(select.value).to.equal('');
+        expect(select.disabled).toBe(true);
+        expect(select.value).toBe('');
       });
     });
   });

+ 38 - 25
tests/test-notebook/src/panel.spec.ts → packages/notebook/test/panel.spec.ts

@@ -1,20 +1,33 @@
 // Copyright (c) Jupyter Development Team.
-// Distributed under the terms of the Modified BSD License.
 
-import { expect } from 'chai';
+import 'jest';
 
 import { Context } from '@jupyterlab/docregistry';
 
-import { INotebookModel, NotebookPanel, Notebook } from '@jupyterlab/notebook';
+import { INotebookModel, NotebookPanel, Notebook } from '../src';
 
 import { Toolbar } from '@jupyterlab/apputils';
 
-import { initNotebookContext, NBTestUtils } from '@jupyterlab/testutils';
+import { initNotebookContext } from '@jupyterlab/testutils';
+import { JupyterServer } from '@jupyterlab/testutils/lib/start_jupyter_server';
+
+import * as utils from './utils';
 
 /**
  * Default data.
  */
-const contentFactory = NBTestUtils.createNotebookPanelFactory();
+const contentFactory = utils.createNotebookPanelFactory();
+
+const server = new JupyterServer();
+
+beforeAll(async () => {
+  jest.setTimeout(20000);
+  await server.start();
+});
+
+afterAll(async () => {
+  await server.shutdown();
+});
 
 describe('@jupyterlab/notebook', () => {
   describe('NotebookPanel', () => {
@@ -30,54 +43,54 @@ describe('@jupyterlab/notebook', () => {
 
     describe('#constructor()', () => {
       it('should create a notebook panel', () => {
-        const content = NBTestUtils.createNotebook();
+        const content = utils.createNotebook();
         const panel = new NotebookPanel({ context, content });
-        expect(panel).to.be.an.instanceof(NotebookPanel);
+        expect(panel).toBeInstanceOf(NotebookPanel);
       });
 
       it('should change notebook to edit mode if we have a single empty code cell', async () => {
-        const panel = NBTestUtils.createNotebookPanel(context);
+        const panel = utils.createNotebookPanel(context);
         const model = panel.content.model;
-        expect(model).to.equal(context.model);
+        expect(model).toBe(context.model);
         await context.initialize(true);
         await context.ready;
-        expect(panel.content.mode).to.equal('edit');
+        expect(panel.content.mode).toBe('edit');
       });
     });
 
     describe('#toolbar', () => {
       it('should be the toolbar used by the widget', () => {
-        const panel = NBTestUtils.createNotebookPanel(context);
-        expect(panel.toolbar).to.be.an.instanceof(Toolbar);
+        const panel = utils.createNotebookPanel(context);
+        expect(panel.toolbar).toBeInstanceOf(Toolbar);
       });
     });
 
     describe('#content', () => {
       it('should be the notebook content widget', () => {
-        const panel = NBTestUtils.createNotebookPanel(context);
-        expect(panel.content).to.be.an.instanceof(Notebook);
+        const panel = utils.createNotebookPanel(context);
+        expect(panel.content).toBeInstanceOf(Notebook);
       });
     });
 
     describe('#context', () => {
       it('should get the document context for the widget', () => {
-        const panel = NBTestUtils.createNotebookPanel(context);
-        expect(panel.context).to.equal(context);
+        const panel = utils.createNotebookPanel(context);
+        expect(panel.context).toBe(context);
       });
     });
 
     describe('#dispose()', () => {
       it('should dispose of the resources used by the widget', () => {
-        const panel = NBTestUtils.createNotebookPanel(context);
+        const panel = utils.createNotebookPanel(context);
         panel.dispose();
-        expect(panel.isDisposed).to.equal(true);
+        expect(panel.isDisposed).toBe(true);
       });
 
       it('should be safe to call more than once', () => {
-        const panel = NBTestUtils.createNotebookPanel(context);
+        const panel = utils.createNotebookPanel(context);
         panel.dispose();
         panel.dispose();
-        expect(panel.isDisposed).to.equal(true);
+        expect(panel.isDisposed).toBe(true);
       });
     });
 
@@ -85,9 +98,9 @@ describe('@jupyterlab/notebook', () => {
       describe('#constructor', () => {
         it('should create a new ContentFactory', () => {
           const factory = new NotebookPanel.ContentFactory({
-            editorFactory: NBTestUtils.editorFactory
+            editorFactory: utils.editorFactory
           });
-          expect(factory).to.be.an.instanceof(NotebookPanel.ContentFactory);
+          expect(factory).toBeInstanceOf(NotebookPanel.ContentFactory);
         });
       });
 
@@ -95,10 +108,10 @@ describe('@jupyterlab/notebook', () => {
         it('should create a notebook widget', () => {
           const options = {
             contentFactory: contentFactory,
-            rendermime: NBTestUtils.defaultRenderMime(),
-            mimeTypeService: NBTestUtils.mimeTypeService
+            rendermime: utils.defaultRenderMime(),
+            mimeTypeService: utils.mimeTypeService
           };
-          expect(contentFactory.createNotebook(options)).to.be.an.instanceof(
+          expect(contentFactory.createNotebook(options)).toBeInstanceOf(
             Notebook
           );
         });

+ 32 - 21
tests/test-notebook/src/tracker.spec.ts → packages/notebook/test/tracker.spec.ts

@@ -1,22 +1,31 @@
 // Copyright (c) Jupyter Development Team.
-// Distributed under the terms of the Modified BSD License.
 
-import { expect } from 'chai';
+import 'jest';
 
 import { Cell } from '@jupyterlab/cells';
 
 import { Context } from '@jupyterlab/docregistry';
 
-import {
-  INotebookModel,
-  NotebookPanel,
-  NotebookTracker
-} from '@jupyterlab/notebook';
+import { INotebookModel, NotebookPanel, NotebookTracker } from '../src';
 
-import { initNotebookContext, NBTestUtils } from '@jupyterlab/testutils';
+import { initNotebookContext } from '@jupyterlab/testutils';
+import { JupyterServer } from '@jupyterlab/testutils/lib/start_jupyter_server';
+
+import * as utils from './utils';
 
 const namespace = 'notebook-tracker-test';
 
+const server = new JupyterServer();
+
+beforeAll(async () => {
+  jest.setTimeout(20000);
+  await server.start();
+});
+
+afterAll(async () => {
+  await server.shutdown();
+});
+
 class TestTracker extends NotebookTracker {
   methods: string[] = [];
 
@@ -41,30 +50,30 @@ describe('@jupyterlab/notebook', () => {
     describe('#constructor()', () => {
       it('should create a NotebookTracker', () => {
         const tracker = new NotebookTracker({ namespace });
-        expect(tracker).to.be.an.instanceof(NotebookTracker);
+        expect(tracker).toBeInstanceOf(NotebookTracker);
       });
     });
 
     describe('#activeCell', () => {
       it('should be `null` if there is no tracked notebook panel', () => {
         const tracker = new NotebookTracker({ namespace });
-        expect(tracker.activeCell).to.be.null;
+        expect(tracker.activeCell).toBeNull();
       });
 
       it('should be `null` if a tracked notebook has no active cell', () => {
         const tracker = new NotebookTracker({ namespace });
-        const panel = NBTestUtils.createNotebookPanel(context);
+        const panel = utils.createNotebookPanel(context);
         panel.content.model!.cells.clear();
         void tracker.add(panel);
-        expect(tracker.activeCell).to.be.null;
+        expect(tracker.activeCell).toBeNull();
       });
 
       it('should be the active cell if a tracked notebook has one', async () => {
         const tracker = new NotebookTracker({ namespace });
-        const panel = NBTestUtils.createNotebookPanel(context);
+        const panel = utils.createNotebookPanel(context);
         await tracker.add(panel);
-        panel.content.model!.fromJSON(NBTestUtils.DEFAULT_CONTENT);
-        expect(tracker.activeCell).to.be.an.instanceof(Cell);
+        panel.content.model!.fromJSON(utils.DEFAULT_CONTENT);
+        expect(tracker.activeCell).toBeInstanceOf(Cell);
         panel.dispose();
       });
     });
@@ -72,16 +81,16 @@ describe('@jupyterlab/notebook', () => {
     describe('#activeCellChanged', () => {
       it('should emit a signal when the active cell changes', async () => {
         const tracker = new NotebookTracker({ namespace });
-        const panel = NBTestUtils.createNotebookPanel(context);
+        const panel = utils.createNotebookPanel(context);
         let count = 0;
         tracker.activeCellChanged.connect(() => {
           count++;
         });
-        panel.content.model!.fromJSON(NBTestUtils.DEFAULT_CONTENT);
+        panel.content.model!.fromJSON(utils.DEFAULT_CONTENT);
         await tracker.add(panel);
-        expect(count).to.equal(1);
+        expect(count).toBe(1);
         panel.content.activeCellIndex = 1;
-        expect(count).to.equal(2);
+        expect(count).toBe(2);
         panel.dispose();
       });
     });
@@ -89,9 +98,11 @@ describe('@jupyterlab/notebook', () => {
     describe('#onCurrentChanged()', () => {
       it('should be called when the active cell changes', async () => {
         const tracker = new TestTracker({ namespace });
-        const panel = NBTestUtils.createNotebookPanel(context);
+        const panel = utils.createNotebookPanel(context);
         await tracker.add(panel);
-        expect(tracker.methods).to.contain('onCurrentChanged');
+        expect(tracker.methods).toEqual(
+          expect.arrayContaining(['onCurrentChanged'])
+        );
       });
     });
   });

+ 72 - 0
packages/notebook/test/utils.ts

@@ -0,0 +1,72 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import { Context } from '@jupyterlab/docregistry';
+
+import { INotebookModel, NotebookPanel, Notebook, NotebookModel } from '../src';
+
+import { NBTestUtils } from '@jupyterlab/testutils';
+
+/**
+ * Local versions of the NBTestUtils that import from `src` instead of `lib`.
+ */
+
+/**
+ * Create a default notebook content factory.
+ */
+export function createNotebookFactory(): Notebook.IContentFactory {
+  return new Notebook.ContentFactory({
+    editorFactory: NBTestUtils.editorFactory
+  });
+}
+
+/**
+ * Create a default notebook panel content factory.
+ */
+export function createNotebookPanelFactory(): NotebookPanel.IContentFactory {
+  return new NotebookPanel.ContentFactory({
+    editorFactory: NBTestUtils.editorFactory
+  });
+}
+
+/**
+ * Create a notebook widget.
+ */
+export function createNotebook(): Notebook {
+  return new Notebook({
+    rendermime: NBTestUtils.defaultRenderMime(),
+    contentFactory: createNotebookFactory(),
+    mimeTypeService: NBTestUtils.mimeTypeService
+  });
+}
+
+/**
+ * Create a notebook panel widget.
+ */
+export function createNotebookPanel(
+  context: Context<INotebookModel>
+): NotebookPanel {
+  return new NotebookPanel({
+    content: createNotebook(),
+    context
+  });
+}
+
+/**
+ * Populate a notebook with default content.
+ */
+export function populateNotebook(notebook: Notebook): void {
+  const model = new NotebookModel();
+  model.fromJSON(NBTestUtils.DEFAULT_CONTENT);
+  notebook.model = model;
+}
+
+export const DEFAULT_CONTENT = NBTestUtils.DEFAULT_CONTENT;
+export const editorFactory = NBTestUtils.editorFactory;
+export const mimeTypeService = NBTestUtils.mimeTypeService;
+export const defaultEditorConfig = NBTestUtils.defaultEditorConfig;
+export const clipboard = NBTestUtils.clipboard;
+
+export function defaultRenderMime() {
+  return NBTestUtils.defaultRenderMime();
+}

File diff suppressed because it is too large
+ 204 - 177
packages/notebook/test/widget.spec.ts


+ 42 - 38
tests/test-notebook/src/widgetfactory.spec.ts → packages/notebook/test/widgetfactory.spec.ts

@@ -1,7 +1,6 @@
 // Copyright (c) Jupyter Development Team.
-// Distributed under the terms of the Modified BSD License.
 
-import { expect } from 'chai';
+import 'jest';
 
 import { toArray } from '@lumino/algorithm';
 
@@ -9,16 +8,25 @@ import { ToolbarButton } from '@jupyterlab/apputils';
 
 import { DocumentRegistry, Context } from '@jupyterlab/docregistry';
 
-import {
-  INotebookModel,
-  NotebookPanel,
-  NotebookWidgetFactory
-} from '@jupyterlab/notebook';
+import { INotebookModel, NotebookPanel, NotebookWidgetFactory } from '../src';
 
-import { initNotebookContext, NBTestUtils } from '@jupyterlab/testutils';
+import { initNotebookContext } from '@jupyterlab/testutils';
+import { JupyterServer } from '@jupyterlab/testutils/lib/start_jupyter_server';
+import * as utils from './utils';
 
-const contentFactory = NBTestUtils.createNotebookPanelFactory();
-const rendermime = NBTestUtils.defaultRenderMime();
+const contentFactory = utils.createNotebookPanelFactory();
+const rendermime = utils.defaultRenderMime();
+
+const server = new JupyterServer();
+
+beforeAll(async () => {
+  jest.setTimeout(20000);
+  await server.start();
+});
+
+afterAll(async () => {
+  await server.shutdown();
+});
 
 function createFactory(
   toolbarFactory?: (widget: NotebookPanel) => DocumentRegistry.IToolbarItem[]
@@ -29,8 +37,8 @@ function createFactory(
     rendermime,
     toolbarFactory,
     contentFactory,
-    mimeTypeService: NBTestUtils.mimeTypeService,
-    editorConfig: NBTestUtils.defaultEditorConfig
+    mimeTypeService: utils.mimeTypeService,
+    editorConfig: utils.defaultEditorConfig
   });
 }
 
@@ -49,16 +57,16 @@ describe('@jupyterlab/notebook', () => {
     describe('#constructor()', () => {
       it('should create a notebook widget factory', () => {
         const factory = createFactory();
-        expect(factory).to.be.an.instanceof(NotebookWidgetFactory);
+        expect(factory).toBeInstanceOf(NotebookWidgetFactory);
       });
     });
 
     describe('#isDisposed', () => {
       it('should get whether the factory has been disposed', () => {
         const factory = createFactory();
-        expect(factory.isDisposed).to.equal(false);
+        expect(factory.isDisposed).toBe(false);
         factory.dispose();
-        expect(factory.isDisposed).to.equal(true);
+        expect(factory.isDisposed).toBe(true);
       });
     });
 
@@ -66,28 +74,28 @@ describe('@jupyterlab/notebook', () => {
       it('should dispose of the resources held by the factory', () => {
         const factory = createFactory();
         factory.dispose();
-        expect(factory.isDisposed).to.equal(true);
+        expect(factory.isDisposed).toBe(true);
       });
 
       it('should be safe to call multiple times', () => {
         const factory = createFactory();
         factory.dispose();
         factory.dispose();
-        expect(factory.isDisposed).to.equal(true);
+        expect(factory.isDisposed).toBe(true);
       });
     });
 
     describe('#editorConfig', () => {
       it('should be the editor config passed into the constructor', () => {
         const factory = createFactory();
-        expect(factory.editorConfig).to.equal(NBTestUtils.defaultEditorConfig);
+        expect(factory.editorConfig).toBe(utils.defaultEditorConfig);
       });
 
       it('should be settable', () => {
         const factory = createFactory();
-        const newConfig = { ...NBTestUtils.defaultEditorConfig };
+        const newConfig = { ...utils.defaultEditorConfig };
         factory.editorConfig = newConfig;
-        expect(factory.editorConfig).to.equal(newConfig);
+        expect(factory.editorConfig).toBe(newConfig);
       });
     });
 
@@ -95,30 +103,28 @@ describe('@jupyterlab/notebook', () => {
       it('should create a new `NotebookPanel` widget', () => {
         const factory = createFactory();
         const panel = factory.createNew(context);
-        expect(panel).to.be.an.instanceof(NotebookPanel);
+        expect(panel).toBeInstanceOf(NotebookPanel);
       });
 
       it('should create a clone of the rendermime', () => {
         const factory = createFactory();
         const panel = factory.createNew(context);
-        expect(panel.content.rendermime).to.not.equal(rendermime);
+        expect(panel.content.rendermime).not.toBe(rendermime);
       });
 
       it('should pass the editor config to the notebook', () => {
         const factory = createFactory();
         const panel = factory.createNew(context);
-        expect(panel.content.editorConfig).to.equal(
-          NBTestUtils.defaultEditorConfig
-        );
+        expect(panel.content.editorConfig).toBe(utils.defaultEditorConfig);
       });
 
       it('should populate the default toolbar items', () => {
         const factory = createFactory();
         const panel = factory.createNew(context);
         const items = toArray(panel.toolbar.names());
-        expect(items).to.contain('save');
-        expect(items).to.contain('restart');
-        expect(items).to.contain('kernelStatus');
+        expect(items).toEqual(expect.arrayContaining(['save']));
+        expect(items).toEqual(expect.arrayContaining(['restart']));
+        expect(items).toEqual(expect.arrayContaining(['kernelStatus']));
       });
 
       it('should populate the customized toolbar items', () => {
@@ -129,22 +135,20 @@ describe('@jupyterlab/notebook', () => {
         const factory = createFactory(toolbarFactory);
         const panel = factory.createNew(context);
         const panel2 = factory.createNew(context);
-        expect(toArray(panel.toolbar.names())).to.deep.equal(['foo', 'bar']);
-        expect(toArray(panel2.toolbar.names())).to.deep.equal(['foo', 'bar']);
-        expect(toArray(panel.toolbar.children()).length).to.equal(2);
-        expect(toArray(panel2.toolbar.children()).length).to.equal(2);
+        expect(toArray(panel.toolbar.names())).toEqual(['foo', 'bar']);
+        expect(toArray(panel2.toolbar.names())).toEqual(['foo', 'bar']);
+        expect(toArray(panel.toolbar.children()).length).toBe(2);
+        expect(toArray(panel2.toolbar.children()).length).toBe(2);
       });
 
       it('should clone from the optional source widget', () => {
         const factory = createFactory();
         const panel = factory.createNew(context);
         const clone = factory.createNew(panel.context, panel);
-        expect(clone).to.be.an.instanceof(NotebookPanel);
-        expect(clone.content.rendermime).to.equal(panel.content.rendermime);
-        expect(clone.content.editorConfig).to.equal(panel.content.editorConfig);
-        expect(clone.content.notebookConfig).to.equal(
-          panel.content.notebookConfig
-        );
+        expect(clone).toBeInstanceOf(NotebookPanel);
+        expect(clone.content.rendermime).toBe(panel.content.rendermime);
+        expect(clone.content.editorConfig).toBe(panel.content.editorConfig);
+        expect(clone.content.notebookConfig).toBe(panel.content.notebookConfig);
       });
     });
   });

+ 75 - 0
packages/notebook/tsconfig.test.json

@@ -0,0 +1,75 @@
+{
+  "extends": "../../tsconfigbase.test",
+  "include": ["src/*", "test/*"],
+  "references": [
+    {
+      "path": "../apputils"
+    },
+    {
+      "path": "../cells"
+    },
+    {
+      "path": "../codeeditor"
+    },
+    {
+      "path": "../coreutils"
+    },
+    {
+      "path": "../docregistry"
+    },
+    {
+      "path": "../nbformat"
+    },
+    {
+      "path": "../observables"
+    },
+    {
+      "path": "../rendermime"
+    },
+    {
+      "path": "../services"
+    },
+    {
+      "path": "../statusbar"
+    },
+    {
+      "path": "../ui-components"
+    },
+    {
+      "path": "../../testutils"
+    },
+    {
+      "path": "../apputils"
+    },
+    {
+      "path": "../cells"
+    },
+    {
+      "path": "../codeeditor"
+    },
+    {
+      "path": "../coreutils"
+    },
+    {
+      "path": "../docregistry"
+    },
+    {
+      "path": "../nbformat"
+    },
+    {
+      "path": "../observables"
+    },
+    {
+      "path": "../rendermime"
+    },
+    {
+      "path": "../services"
+    },
+    {
+      "path": "../statusbar"
+    },
+    {
+      "path": "../ui-components"
+    }
+  ]
+}

+ 2 - 1
packages/services/src/kernel/default.ts

@@ -547,7 +547,8 @@ export class KernelConnection implements Kernel.IKernelConnection {
     }
 
     if (reply.content.status !== 'ok') {
-      throw new Error('Kernel info reply errored');
+      this._info.reject('Kernel info reply errored');
+      return reply;
     }
 
     this._info.resolve(reply.content);

+ 0 - 1
tests/test-notebook/karma-cov.conf.js

@@ -1 +0,0 @@
-module.exports = require('../karma-cov.conf');

+ 0 - 1
tests/test-notebook/karma.conf.js

@@ -1 +0,0 @@
-module.exports = require('../karma.conf');

+ 0 - 46
tests/test-notebook/package.json

@@ -1,46 +0,0 @@
-{
-  "name": "@jupyterlab/test-notebook",
-  "version": "2.1.0",
-  "private": true,
-  "scripts": {
-    "build": "tsc -b",
-    "clean": "rimraf build && rimraf coverage",
-    "coverage": "python run-test.py --browsers=ChromeHeadless karma-cov.conf.js",
-    "test": "jlpm run test:firefox-headless",
-    "test:chrome": "python run-test.py --browsers=Chrome karma.conf.js",
-    "test:chrome-headless": "python run-test.py --browsers=ChromeHeadless karma.conf.js",
-    "test:debug": "python run-test.py  --browsers=Chrome --singleRun=false --debug=true --browserNoActivityTimeout=10000000 --browserDisconnectTimeout=10000000 karma.conf.js",
-    "test:debug:chrome-headless": "python run-test.py  --browsers=ChromeHeadless --singleRun=false --debug=true --browserNoActivityTimeout=10000000 --browserDisconnectTimeout=10000000 karma.conf.js",
-    "test:firefox": "python run-test.py --browsers=Firefox karma.conf.js",
-    "test:firefox-headless": "python run-test.py --browsers=FirefoxHeadless karma.conf.js",
-    "test:ie": "python run-test.py  --browsers=IE karma.conf.js",
-    "test:watch": "python run-test.py  --browsers=Chrome --singleRun=false --debug=true --watch --browserNoActivityTimeout=10000000 --browserDisconnectTimeout=10000000 karma.conf.js",
-    "watch": "tsc -b --watch",
-    "watch:src": "tsc -p src --watch"
-  },
-  "dependencies": {
-    "@jupyterlab/apputils": "^2.1.0",
-    "@jupyterlab/cells": "^2.1.0",
-    "@jupyterlab/codemirror": "^2.1.0",
-    "@jupyterlab/docregistry": "^2.1.0",
-    "@jupyterlab/nbformat": "^2.1.0",
-    "@jupyterlab/notebook": "^2.1.0",
-    "@jupyterlab/observables": "^3.1.0",
-    "@jupyterlab/testutils": "^2.1.0",
-    "@lumino/algorithm": "^1.2.3",
-    "@lumino/coreutils": "^1.4.2",
-    "@lumino/messaging": "^1.3.3",
-    "@lumino/widgets": "^1.11.1",
-    "chai": "^4.2.0",
-    "simulate-event": "~1.4.0"
-  },
-  "devDependencies": {
-    "@types/chai": "^4.2.7",
-    "@types/mocha": "^7.0.2",
-    "karma": "^4.4.1",
-    "karma-chrome-launcher": "~3.1.0",
-    "puppeteer": "~2.0.0",
-    "rimraf": "~3.0.0",
-    "typescript": "~3.7.3"
-  }
-}

+ 0 - 10
tests/test-notebook/run-test.py

@@ -1,10 +0,0 @@
-# Copyright (c) Jupyter Development Team.
-# Distributed under the terms of the Modified BSD License.
-
-import os
-from jupyterlab.tests.test_app import run_karma
-
-HERE = os.path.realpath(os.path.dirname(__file__))
-
-if __name__ == '__main__':
-    run_karma(HERE)

+ 0 - 37
tests/test-notebook/tsconfig.json

@@ -1,37 +0,0 @@
-{
-  "extends": "../../tsconfigbase",
-  "compilerOptions": {
-    "outDir": "build",
-    "types": ["mocha"],
-    "composite": false,
-    "rootDir": "src",
-    "skipLibCheck": true
-  },
-  "include": ["src/*"],
-  "references": [
-    {
-      "path": "../../packages/apputils"
-    },
-    {
-      "path": "../../packages/cells"
-    },
-    {
-      "path": "../../packages/codemirror"
-    },
-    {
-      "path": "../../packages/docregistry"
-    },
-    {
-      "path": "../../packages/nbformat"
-    },
-    {
-      "path": "../../packages/notebook"
-    },
-    {
-      "path": "../../packages/observables"
-    },
-    {
-      "path": "../../testutils"
-    }
-  ]
-}

+ 9 - 0
testutils/src/jest-shim.ts

@@ -52,3 +52,12 @@ process.on('unhandledRejection', (error, promise) => {
   }
   promise.catch(err => console.error('promise rejected', err));
 });
+
+(window as any).getSelection = function getSelection() {
+  return {
+    selectAllChildren: () => {
+      // no-op
+    },
+    toString: () => ''
+  };
+};

+ 0 - 5
yarn.lock

@@ -3625,11 +3625,6 @@
   resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6"
   integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=
 
-"@types/mocha@^7.0.2":
-  version "7.0.2"
-  resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.2.tgz#b17f16cf933597e10d6d78eae3251e692ce8b0ce"
-  integrity sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==
-
 "@types/node-fetch@^2.5.4":
   version "2.5.4"
   resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.4.tgz#5245b6d8841fc3a6208b82291119bc11c4e0ce44"

Some files were not shown because too many files changed in this diff