|
@@ -4,7 +4,7 @@
|
|
|
import expect = require('expect.js');
|
|
|
|
|
|
import {
|
|
|
- ObservableList
|
|
|
+ ListChangeType
|
|
|
} from 'phosphor-observablelist';
|
|
|
|
|
|
import {
|
|
@@ -12,10 +12,59 @@ import {
|
|
|
} from '../../../../lib/notebook/output-area/model';
|
|
|
|
|
|
import {
|
|
|
- IStream
|
|
|
+ nbformat
|
|
|
} from '../../../../lib/notebook/notebook/nbformat';
|
|
|
|
|
|
|
|
|
+/**
|
|
|
+ * The default outputs used for testing.
|
|
|
+ */
|
|
|
+export
|
|
|
+const DEFAULT_OUTPUTS: nbformat.IOutput[] = [
|
|
|
+ {
|
|
|
+ name: 'stdout',
|
|
|
+ output_type: 'stream',
|
|
|
+ text: [
|
|
|
+ 'hello world\n',
|
|
|
+ '0\n',
|
|
|
+ '1\n',
|
|
|
+ '2\n'
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'stderr',
|
|
|
+ output_type: 'stream',
|
|
|
+ text: [
|
|
|
+ 'output to stderr\n'
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'stderr',
|
|
|
+ output_type: 'stream',
|
|
|
+ text: [
|
|
|
+ 'output to stderr2\n'
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ output_type: 'execute_result',
|
|
|
+ execution_count: 1,
|
|
|
+ data: { 'text/plain': 'foo' },
|
|
|
+ metadata: {}
|
|
|
+ },
|
|
|
+ {
|
|
|
+ output_type: 'display_data',
|
|
|
+ data: { 'text/plain': 'hello, world' },
|
|
|
+ metadata: {}
|
|
|
+ },
|
|
|
+ {
|
|
|
+ output_type: 'error',
|
|
|
+ ename: 'foo',
|
|
|
+ evalue: 'bar',
|
|
|
+ traceback: ['fizz', 'buzz']
|
|
|
+ }
|
|
|
+];
|
|
|
+
|
|
|
+
|
|
|
describe('notebook/output-area/model', () => {
|
|
|
|
|
|
describe('OutputAreaModel', () => {
|
|
@@ -24,164 +73,97 @@ describe('notebook/output-area/model', () => {
|
|
|
|
|
|
it('should create an output area model', () => {
|
|
|
let model = new OutputAreaModel();
|
|
|
- expect(model instanceof OutputAreaModel).to.be(true);
|
|
|
+ expect(model).to.be.an(OutputAreaModel);
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
- describe('#stateChanged', () => {
|
|
|
+ describe('#changed', () => {
|
|
|
|
|
|
- it('should be emitted when the state changes', () => {
|
|
|
+ it('should be emitted when the model changes', () => {
|
|
|
let model = new OutputAreaModel();
|
|
|
let called = false;
|
|
|
- model.stateChanged.connect((editor, change) => {
|
|
|
- expect(change.name).to.be('trusted');
|
|
|
- expect(change.oldValue).to.be(false);
|
|
|
- expect(change.newValue).to.be(true);
|
|
|
+ model.changed.connect((sender, args) => {
|
|
|
+ expect(sender).to.be(model);
|
|
|
+ expect(args.type).to.be(ListChangeType.Add);
|
|
|
+ expect(args.oldIndex).to.be(-1);
|
|
|
+ expect(args.newIndex).to.be(0);
|
|
|
+ expect(args.oldValue).to.be(void 0);
|
|
|
+ // TODO: use deepEqual when we update nbformat
|
|
|
called = true;
|
|
|
});
|
|
|
- model.trusted = true;
|
|
|
+ model.add(DEFAULT_OUTPUTS[0]);
|
|
|
expect(called).to.be(true);
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
- describe('#outputs', () => {
|
|
|
+ describe('#length', () => {
|
|
|
|
|
|
- it('should be an observable list', () => {
|
|
|
+ it('should get the length of the items in the model', () => {
|
|
|
let model = new OutputAreaModel();
|
|
|
- expect(model.outputs instanceof ObservableList).to.be(true);
|
|
|
+ expect(model.length).to.be(0);
|
|
|
+ model.add(DEFAULT_OUTPUTS[0]);
|
|
|
+ expect(model.length).to.be(1);
|
|
|
});
|
|
|
|
|
|
it('should be read-only', () => {
|
|
|
let model = new OutputAreaModel();
|
|
|
- expect(() => { model.outputs = null; }).to.throwError();
|
|
|
- });
|
|
|
-
|
|
|
- });
|
|
|
-
|
|
|
- describe('#trusted', () => {
|
|
|
-
|
|
|
- it('should default to false', () => {
|
|
|
- let model = new OutputAreaModel();
|
|
|
- expect(model.trusted).to.be(false);
|
|
|
- });
|
|
|
-
|
|
|
- it('should emit a stateChanged signal when changed', () => {
|
|
|
- let model = new OutputAreaModel();
|
|
|
- let called = false;
|
|
|
- model.stateChanged.connect((editor, change) => {
|
|
|
- expect(change.name).to.be('trusted');
|
|
|
- expect(change.oldValue).to.be(false);
|
|
|
- expect(change.newValue).to.be(true);
|
|
|
- called = true;
|
|
|
- });
|
|
|
- model.trusted = true;
|
|
|
- expect(called).to.be(true);
|
|
|
- });
|
|
|
-
|
|
|
- it('should not emit the signal when there is no change', () => {
|
|
|
- let model = new OutputAreaModel();
|
|
|
- let called = false;
|
|
|
- model.stateChanged.connect((editor, change) => {
|
|
|
- called = true;
|
|
|
- });
|
|
|
- model.trusted = false;
|
|
|
- expect(called).to.be(false);
|
|
|
+ expect(() => { model.length = 0; }).to.throwError();
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
- describe('#fixedHeight', () => {
|
|
|
-
|
|
|
- it('should default to false', () => {
|
|
|
- let model = new OutputAreaModel();
|
|
|
- expect(model.fixedHeight).to.be(false);
|
|
|
- });
|
|
|
+ describe('#isDisposed', () => {
|
|
|
|
|
|
- it('should emit a stateChanged signal when changed', () => {
|
|
|
+ it('should test whether the model is disposed', () => {
|
|
|
let model = new OutputAreaModel();
|
|
|
- let called = false;
|
|
|
- model.stateChanged.connect((editor, change) => {
|
|
|
- expect(change.name).to.be('fixedHeight');
|
|
|
- expect(change.oldValue).to.be(false);
|
|
|
- expect(change.newValue).to.be(true);
|
|
|
- called = true;
|
|
|
- });
|
|
|
- model.fixedHeight = true;
|
|
|
- expect(called).to.be(true);
|
|
|
+ expect(model.isDisposed).to.be(false);
|
|
|
+ model.dispose();
|
|
|
+ expect(model.isDisposed).to.be(true);
|
|
|
});
|
|
|
|
|
|
- it('should not emit the signal when there is no change', () => {
|
|
|
+ it('should be read-only', () => {
|
|
|
let model = new OutputAreaModel();
|
|
|
- let called = false;
|
|
|
- model.stateChanged.connect((editor, change) => {
|
|
|
- called = true;
|
|
|
- });
|
|
|
- model.fixedHeight = false;
|
|
|
- expect(called).to.be(false);
|
|
|
+ expect(() => { model.isDisposed = true; }).to.throwError();
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
- describe('#collapsed', () => {
|
|
|
-
|
|
|
- it('should default to false', () => {
|
|
|
- let model = new OutputAreaModel();
|
|
|
- expect(model.collapsed).to.be(false);
|
|
|
- });
|
|
|
-
|
|
|
- it('should emit a stateChanged signal when changed', () => {
|
|
|
- let model = new OutputAreaModel();
|
|
|
- let called = false;
|
|
|
- model.stateChanged.connect((editor, change) => {
|
|
|
- expect(change.name).to.be('collapsed');
|
|
|
- expect(change.oldValue).to.be(false);
|
|
|
- expect(change.newValue).to.be(true);
|
|
|
- called = true;
|
|
|
- });
|
|
|
- model.collapsed = true;
|
|
|
- expect(called).to.be(true);
|
|
|
- });
|
|
|
+ describe('#dispose()', () => {
|
|
|
|
|
|
- it('should not emit the signal when there is no change', () => {
|
|
|
+ it('should dispose of the resources used by the model', () => {
|
|
|
let model = new OutputAreaModel();
|
|
|
- let called = false;
|
|
|
- model.stateChanged.connect((editor, change) => {
|
|
|
- called = true;
|
|
|
- });
|
|
|
- model.collapsed = false;
|
|
|
- expect(called).to.be(false);
|
|
|
+ model.add(DEFAULT_OUTPUTS[0]);
|
|
|
+ model.dispose();
|
|
|
+ expect(model.isDisposed).to.be(true);
|
|
|
+ expect(model.length).to.be(0);
|
|
|
});
|
|
|
|
|
|
- });
|
|
|
-
|
|
|
- describe('#isDisposed', () => {
|
|
|
-
|
|
|
- it('should indicate whether the model is disposed', () => {
|
|
|
+ it('should be safe to call more than once', () => {
|
|
|
let model = new OutputAreaModel();
|
|
|
- expect(model.isDisposed).to.be(false);
|
|
|
+ model.dispose();
|
|
|
model.dispose();
|
|
|
expect(model.isDisposed).to.be(true);
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
- describe('#dispose()', () => {
|
|
|
+ describe('#get()', () => {
|
|
|
|
|
|
- it('should clear signal data on the model', () => {
|
|
|
+ it('should get the item at the specified index', () => {
|
|
|
let model = new OutputAreaModel();
|
|
|
- let called = false;
|
|
|
- model.stateChanged.connect(() => { called = true; });
|
|
|
- model.dispose();
|
|
|
- model.collapsed = true;
|
|
|
- expect(called).to.be(false);
|
|
|
+ model.add(DEFAULT_OUTPUTS[0]);
|
|
|
+ let output = model.get(0);
|
|
|
+ expect(output).to.not.be(DEFAULT_OUTPUTS[0]);
|
|
|
+ // TODO: use deepEqual when nbformat is updated.
|
|
|
+ expect(output.output_type).to.be(DEFAULT_OUTPUTS[0].output_type);
|
|
|
});
|
|
|
|
|
|
- it('should be safe to call multiple times', () => {
|
|
|
+ it('should return `undefined` if out of range', () => {
|
|
|
let model = new OutputAreaModel();
|
|
|
- model.dispose();
|
|
|
- model.dispose();
|
|
|
+ model.add(DEFAULT_OUTPUTS[0]);
|
|
|
+ expect(model.get(1)).to.be(void 0);
|
|
|
});
|
|
|
|
|
|
});
|
|
@@ -189,38 +171,18 @@ describe('notebook/output-area/model', () => {
|
|
|
describe('#add()', () => {
|
|
|
|
|
|
it('should add an output', () => {
|
|
|
- let output: IStream = {
|
|
|
- output_type: 'stream',
|
|
|
- name: 'stdout',
|
|
|
- text: 'foo\nbar'
|
|
|
- };
|
|
|
let model = new OutputAreaModel();
|
|
|
- model.add(output);
|
|
|
- expect(model.outputs.length).to.be(1);
|
|
|
+ model.add(DEFAULT_OUTPUTS[0]);
|
|
|
+ expect(model.length).to.be(1);
|
|
|
});
|
|
|
|
|
|
it('should consolidate consecutive stream outputs of the same kind', () => {
|
|
|
- let output: IStream = {
|
|
|
- output_type: 'stream',
|
|
|
- name: 'stdout',
|
|
|
- text: 'foo\nbar'
|
|
|
- };
|
|
|
let model = new OutputAreaModel();
|
|
|
- model.add(output);
|
|
|
- output = {
|
|
|
- output_type: 'stream',
|
|
|
- name: 'stdout',
|
|
|
- text: 'fizz\buzz'
|
|
|
- };
|
|
|
- model.add(output);
|
|
|
- expect(model.outputs.length).to.be(1);
|
|
|
- output = {
|
|
|
- output_type: 'stream',
|
|
|
- name: 'stderr',
|
|
|
- text: 'oh no!'
|
|
|
- };
|
|
|
- model.add(output);
|
|
|
- expect(model.outputs.length).to.be(2);
|
|
|
+ model.add(DEFAULT_OUTPUTS[0]);
|
|
|
+ model.add(DEFAULT_OUTPUTS[1]);
|
|
|
+ expect(model.length).to.be(2);
|
|
|
+ model.add(DEFAULT_OUTPUTS[2]);
|
|
|
+ expect(model.length).to.be(2);
|
|
|
});
|
|
|
|
|
|
});
|
|
@@ -228,35 +190,21 @@ describe('notebook/output-area/model', () => {
|
|
|
describe('#clear()', () => {
|
|
|
|
|
|
it('should clear all of the output', () => {
|
|
|
- let output: IStream = {
|
|
|
- output_type: 'stream',
|
|
|
- name: 'stdout',
|
|
|
- text: 'foo\nbar'
|
|
|
- };
|
|
|
let model = new OutputAreaModel();
|
|
|
- model.add(output);
|
|
|
+ for (let output of DEFAULT_OUTPUTS) {
|
|
|
+ model.add(output);
|
|
|
+ }
|
|
|
model.clear();
|
|
|
- expect(model.outputs.length).to.be(0);
|
|
|
+ expect(model.length).to.be(0);
|
|
|
});
|
|
|
|
|
|
it('should wait for next add if requested', () => {
|
|
|
- let output: IStream = {
|
|
|
- output_type: 'stream',
|
|
|
- name: 'stdout',
|
|
|
- text: 'foo\nbar'
|
|
|
- };
|
|
|
let model = new OutputAreaModel();
|
|
|
- model.add(output);
|
|
|
+ model.add(DEFAULT_OUTPUTS[0]);
|
|
|
model.clear(true);
|
|
|
- expect(model.outputs.length).to.be(1);
|
|
|
- let output2 = {
|
|
|
- output_type: 'error',
|
|
|
- ename: 'foo',
|
|
|
- evalue: '',
|
|
|
- traceback: ['']
|
|
|
- };
|
|
|
- model.add(output2);
|
|
|
- expect(model.outputs.length).to.be(1);
|
|
|
+ expect(model.length).to.be(1);
|
|
|
+ model.add(DEFAULT_OUTPUTS[1]);
|
|
|
+ expect(model.length).to.be(1);
|
|
|
});
|
|
|
});
|
|
|
|