ソースを参照

CompletionWidget keydown tests, bugfix in widget.

A. Darian 8 年 前
コミット
9099241813
2 ファイル変更173 行追加25 行削除
  1. 1 1
      src/notebook/completion/widget.ts
  2. 172 24
      test/src/notebook/completion/widget.spec.ts

+ 1 - 1
src/notebook/completion/widget.ts

@@ -329,7 +329,7 @@ class CompletionWidget extends Widget {
       }
       target = target.parentElement;
     }
-    this.hide();
+    this._model.reset();
   }
 
   /**

+ 172 - 24
test/src/notebook/completion/widget.spec.ts

@@ -24,6 +24,8 @@ const TEST_ITEM_CLASS = 'jp-TestItem';
 
 const ITEM_CLASS = 'jp-Completion-item';
 
+const ACTIVE_CLASS = 'jp-mod-active';
+
 
 class CustomRenderer extends CompletionWidget.Renderer {
   createItemNode(item: ICompletionItem): HTMLLIElement {
@@ -215,20 +217,168 @@ describe('notebook/completion/widget', () => {
         widget.dispose();
       });
 
+      context('keydown', () => {
+
+        it('should reset if keydown is outside reference', () => {
+          let reference = new Widget();
+          let model = new CompletionModel();
+          let options: CompletionWidget.IOptions = { model, reference };
+          model.options = ['foo', 'bar'];
+          reference.attach(document.body);
+
+          let widget = new CompletionWidget(options);
+
+          widget.attach(document.body);
+          sendMessage(widget, Widget.MsgUpdateRequest);
+          expect(widget.isHidden).to.be(false);
+          expect(model.options).to.be.ok();
+          simulate(document.body, 'keydown', { keyCode: 70 }); // F
+          sendMessage(widget, Widget.MsgUpdateRequest);
+          expect(widget.isHidden).to.be(true);
+          expect(model.options).to.not.be.ok();
+          widget.dispose();
+          reference.dispose();
+        });
+
+        it('should reset on escape key', () => {
+          let reference = new Widget();
+          let model = new CompletionModel();
+          let options: CompletionWidget.IOptions = { model, reference };
+          model.options = ['foo', 'bar'];
+          reference.attach(document.body);
+
+          let widget = new CompletionWidget(options);
+
+          widget.attach(document.body);
+          sendMessage(widget, Widget.MsgUpdateRequest);
+          expect(widget.isHidden).to.be(false);
+          expect(model.options).to.be.ok();
+          simulate(reference.node, 'keydown', { keyCode: 27 }); // Escape
+          sendMessage(widget, Widget.MsgUpdateRequest);
+          expect(widget.isHidden).to.be(true);
+          expect(model.options).to.not.be.ok();
+          widget.dispose();
+          reference.dispose();
+        });
+
+        it('should trigger a selected signal on enter key', () => {
+          let reference = new Widget();
+          let model = new TestModel();
+          let options: CompletionWidget.IOptions = { model, reference };
+          let value = '';
+          let listener = (sender: any, selected: string) => {
+            value = selected;
+          };
+          model.options = ['foo', 'bar', 'baz'];
+          reference.attach(document.body);
+
+          let widget = new CompletionWidget(options);
+
+          widget.selected.connect(listener);
+          widget.attach(document.body);
+          sendMessage(widget, Widget.MsgUpdateRequest);
+          expect(value).to.be('');
+          simulate(reference.node, 'keydown', { keyCode: 13 }); // Enter
+          expect(value).to.be('foo');
+          widget.dispose();
+          reference.dispose();
+        });
+
+        it('should select the item below and cycle back on down or tab', () => {
+          let reference = new Widget();
+          let model = new CompletionModel();
+          let options: CompletionWidget.IOptions = { model, reference };
+          model.options = ['foo', 'bar', 'baz'];
+          reference.attach(document.body);
+
+          let widget = new CompletionWidget(options);
+          let target = document.createElement('div');
+
+          reference.node.appendChild(target);
+          widget.attach(document.body);
+          sendMessage(widget, Widget.MsgUpdateRequest);
+
+          let items = widget.node.querySelectorAll(`.${ITEM_CLASS}`);
+
+          expect(items[0].classList).to.contain(ACTIVE_CLASS);
+          expect(items[1].classList).to.not.contain(ACTIVE_CLASS);
+          expect(items[2].classList).to.not.contain(ACTIVE_CLASS);
+          simulate(target, 'keydown', { keyCode: 40 });  // Down
+          expect(items[0].classList).to.not.contain(ACTIVE_CLASS);
+          expect(items[1].classList).to.contain(ACTIVE_CLASS);
+          expect(items[2].classList).to.not.contain(ACTIVE_CLASS);
+          simulate(target, 'keydown', { keyCode: 40 });  // Down
+          expect(items[0].classList).to.not.contain(ACTIVE_CLASS);
+          expect(items[1].classList).to.not.contain(ACTIVE_CLASS);
+          expect(items[2].classList).to.contain(ACTIVE_CLASS);
+          simulate(target, 'keydown', { keyCode: 40 });  // Down
+          expect(items[0].classList).to.contain(ACTIVE_CLASS);
+          expect(items[1].classList).to.not.contain(ACTIVE_CLASS);
+          expect(items[2].classList).to.not.contain(ACTIVE_CLASS);
+          simulate(target, 'keydown', { keyCode: 9 });   // Tab
+          expect(items[0].classList).to.not.contain(ACTIVE_CLASS);
+          expect(items[1].classList).to.contain(ACTIVE_CLASS);
+          expect(items[2].classList).to.not.contain(ACTIVE_CLASS);
+          simulate(target, 'keydown', { keyCode: 9 });   // Tab
+          expect(items[0].classList).to.not.contain(ACTIVE_CLASS);
+          expect(items[1].classList).to.not.contain(ACTIVE_CLASS);
+          expect(items[2].classList).to.contain(ACTIVE_CLASS);
+          simulate(target, 'keydown', { keyCode: 9 });   // Tab
+          expect(items[0].classList).to.contain(ACTIVE_CLASS);
+          expect(items[1].classList).to.not.contain(ACTIVE_CLASS);
+          expect(items[2].classList).to.not.contain(ACTIVE_CLASS);
+          widget.dispose();
+          reference.dispose();
+        });
+
+        it('should select the item above and cycle back on up', () => {
+          let reference = new Widget();
+          let model = new CompletionModel();
+          let options: CompletionWidget.IOptions = { model, reference };
+          model.options = ['foo', 'bar', 'baz'];
+          reference.attach(document.body);
+
+          let widget = new CompletionWidget(options);
+
+          widget.attach(document.body);
+          sendMessage(widget, Widget.MsgUpdateRequest);
+
+          let items = widget.node.querySelectorAll(`.${ITEM_CLASS}`);
+
+          expect(items[0].classList).to.contain(ACTIVE_CLASS);
+          expect(items[1].classList).to.not.contain(ACTIVE_CLASS);
+          expect(items[2].classList).to.not.contain(ACTIVE_CLASS);
+          simulate(reference.node, 'keydown', { keyCode: 38 }); // Up
+          expect(items[0].classList).to.not.contain(ACTIVE_CLASS);
+          expect(items[1].classList).to.not.contain(ACTIVE_CLASS);
+          expect(items[2].classList).to.contain(ACTIVE_CLASS);
+          simulate(reference.node, 'keydown', { keyCode: 38 }); // Up
+          expect(items[0].classList).to.not.contain(ACTIVE_CLASS);
+          expect(items[1].classList).to.contain(ACTIVE_CLASS);
+          expect(items[2].classList).to.not.contain(ACTIVE_CLASS);
+          simulate(reference.node, 'keydown', { keyCode: 38 }); // Up
+          expect(items[0].classList).to.contain(ACTIVE_CLASS);
+          expect(items[1].classList).to.not.contain(ACTIVE_CLASS);
+          expect(items[2].classList).to.not.contain(ACTIVE_CLASS);
+          widget.dispose();
+          reference.dispose();
+        });
+
+      });
+
       context('mousedown', () => {
 
         it('should trigger a selected signal on mouse down', () => {
-          let options: CompletionWidget.IOptions = {
-            model: new TestModel(),
-            reference: new Widget()
-          };
+          let reference = new Widget();
+          let model = new TestModel();
+          let options: CompletionWidget.IOptions = { model, reference };
           let value = '';
           let listener = (sender: any, selected: string) => {
             value = selected;
           };
-          options.model.options = ['foo', 'bar', 'baz'];
-          (options.model as TestModel).setQuery('b');
-          options.reference.attach(document.body);
+          model.options = ['foo', 'bar', 'baz'];
+          model.setQuery('b');
+          reference.attach(document.body);
 
           let widget = new CompletionWidget(options);
 
@@ -236,26 +386,25 @@ describe('notebook/completion/widget', () => {
           widget.attach(document.body);
           sendMessage(widget, Widget.MsgUpdateRequest);
 
-          let items = widget.node.querySelectorAll(`.${ITEM_CLASS} mark`);
+          let item = widget.node.querySelectorAll(`.${ITEM_CLASS} mark`)[1];
 
           expect(value).to.be('');
-          simulate(items[1], 'mousedown');
+          simulate(item, 'mousedown');
           expect(value).to.be('baz');
           widget.dispose();
-          options.reference.dispose();
+          reference.dispose();
         });
 
         it('should ignore a mouse down that misses an item', () => {
-          let options: CompletionWidget.IOptions = {
-            model: new CompletionModel(),
-            reference: new Widget()
-          };
+          let reference = new Widget();
+          let model = new CompletionModel();
+          let options: CompletionWidget.IOptions = { model, reference };
           let value = '';
           let listener = (sender: any, selected: string) => {
             value = selected;
           };
-          options.model.options = ['foo', 'bar'];
-          options.reference.attach(document.body);
+          model.options = ['foo', 'bar'];
+          reference.attach(document.body);
 
           let widget = new CompletionWidget(options);
 
@@ -266,20 +415,19 @@ describe('notebook/completion/widget', () => {
           simulate(widget.node, 'mousedown');
           expect(value).to.be('');
           widget.dispose();
-          options.reference.dispose();
+          reference.dispose();
         });
 
         it('should hide widget if mouse down misses it', (done) => {
-          let options: CompletionWidget.IOptions = {
-            model: new CompletionModel(),
-            reference: new Widget()
-          };
+          let reference = new Widget();
+          let model = new CompletionModel();
+          let options: CompletionWidget.IOptions = { model, reference };
           let value = '';
           let listener = (sender: any, selected: string) => {
             value = selected;
           };
-          options.model.options = ['foo', 'bar'];
-          options.reference.attach(document.body);
+          model.options = ['foo', 'bar'];
+          reference.attach(document.body);
 
           let widget = new CompletionWidget(options);
 
@@ -291,7 +439,7 @@ describe('notebook/completion/widget', () => {
           requestAnimationFrame(() => {
             expect(widget.isHidden).to.be(true);
             widget.dispose();
-            options.reference.dispose();
+            reference.dispose();
             done();
           });
         });