Sfoglia il codice sorgente

Merge pull request #6522 from fcollonval/fix-6378

Remove `Dialog.prompt` (use `InputDialog.getXXX` instead)
Jason Grout 5 anni fa
parent
commit
652a0975a2

+ 67 - 0
docs/source/developer/ui_helpers.rst

@@ -0,0 +1,67 @@
+User Interface Helpers
+----------------------
+
+JupyterLab comes with helpers to show or request simple information from a user.
+Those speed up development and ensure a common look and feel.
+
+Dialogs
+~~~~~~~
+
+Message Dialogs
+'''''''''''''''
+
+Helper functions to show a message to the user are available in the ``apputils`` package.
+These dialogs return a ``Promise`` resolving when the user dismisses the dialog.
+
+There is one helper:
+
+* ``showErrorMessage`` : show an error message dialog.
+
+
+Input Dialogs
+'''''''''''''
+
+Helper functions to request a single input from the user are available in the ``apputils``
+package within the ``InputDialog`` namespace. There are four helpers:
+
+* ``getBoolean`` : request a boolean through a checkbox.
+* ``getItem`` : request a item from a list; the list may be editable.
+* ``getNumber`` : request a number; if the user input is not a valid number, NaN is returned.
+* ``getText`` : request a short text.
+
+All dialogs are built on the standard ``Dialog``. Therefore the helper functions each return
+a ``Promise`` resolving in a ``Dialog.IResult`` object.
+
+.. code:: typescript
+
+    // Request a boolean
+    InputDialog.getBoolean({ title: 'Check or not?' }).then(value => {
+      console.log('boolean ' + value.value);
+    });
+
+    // Request a choice from a list
+    InputDialog.getItem({
+      title: 'Pick a choice',
+      items: ['1', '2']
+    }).then(value => {
+      console.log('item ' + value.value);
+    });
+
+    // Request a choice from a list or specify your own choice
+    InputDialog.getItem({
+      title: 'Pick a choice or write your own',
+      items: ['1', '2'],
+      editable: true
+    }).then(value => {
+      console.log('editable item ' + value.value);
+    });
+
+    // Request a number
+    InputDialog.getNumber({ title: 'How much?' }).then(value => {
+      console.log('number ' + value.value);
+    });
+
+    // Request a text
+    InputDialog.getText({ title: 'Provide a text' }).then(value => {
+      console.log('text ' + value.value);
+    });

+ 1 - 0
docs/source/index.rst

@@ -58,6 +58,7 @@ JupyterLab is the next-generation web-based user interface for Project Jupyter.
    developer/virtualdom
    developer/adding_content
    developer/examples
+   developer/ui_helpers
    developer/terminology
    developer/xkcd_extension_tutorial
 

+ 0 - 73
packages/apputils/src/dialog.ts

@@ -359,11 +359,6 @@ export namespace Dialog {
    */
   export type Header = React.ReactElement<any> | string;
 
-  /**
-   * A simple type for prompt widget
-   */
-  type PromptValue = string | number | boolean;
-
   /**
    * A widget used as a dialog body.
    */
@@ -567,24 +562,6 @@ export namespace Dialog {
     return createButton(options);
   }
 
-  /**
-   * Simple dialog to prompt for a value
-   * @param prompt Text to show on the prompt
-   * @param defaultValue Initial value
-   * @returns a Promise which will resolve with the value entered by user.
-   */
-  export function prompt<T extends PromptValue>(
-    prompt: string,
-    defaultValue: PromptValue
-  ): Promise<Dialog.IResult<T>> {
-    return showDialog({
-      title: prompt,
-      body: new PromptWidget<T>(defaultValue as T),
-      buttons: [Dialog.cancelButton(), Dialog.okButton()],
-      focusNodeSelector: 'input'
-    });
-  }
-
   /**
    * Disposes all dialog instances.
    *
@@ -598,56 +575,6 @@ export namespace Dialog {
     });
   }
 
-  /**
-   * Create and show a prompt dialog
-   */
-  class PromptWidget<T extends PromptValue> extends Widget {
-    constructor(value: T) {
-      let body = document.createElement('div');
-      let input = document.createElement('input');
-      if (typeof value === 'string') {
-        input.type = 'text';
-        if (value) {
-          input.value = value;
-        }
-      }
-      if (typeof value === 'number') {
-        input.type = 'number';
-        if (value) {
-          input.value = value.toFixed(2);
-        }
-      }
-      if (typeof value === 'boolean') {
-        input.type = 'checkbox';
-        input.checked = value;
-      }
-      body.appendChild(input);
-      super({ node: body });
-    }
-
-    /**
-     * Get the input text node.
-     */
-    get inputNode(): HTMLInputElement {
-      return this.node.getElementsByTagName('input')[0] as HTMLInputElement;
-    }
-
-    /**
-     * Get the value of the widget.
-     */
-    getValue(): T {
-      if (this.inputNode.type === 'number') {
-        // In this branch T extends number.
-        return parseFloat(this.inputNode.value) as T;
-      }
-      if (this.inputNode.type === 'checkbox') {
-        // In this branch T extends boolean.
-        return this.inputNode.checked as T;
-      }
-      return this.inputNode.value as T;
-    }
-  }
-
   /**
    * The default implementation of a dialog renderer.
    */

+ 156 - 69
packages/apputils/src/inputdialog.ts

@@ -3,84 +3,101 @@
 
 import { Widget } from '@phosphor/widgets';
 
-import { Dialog } from './dialog';
+import { Dialog, showDialog } from './dialog';
 import { Styling } from './styling';
 
 const INPUT_DIALOG_CLASS = 'jp-Input-Dialog';
 
 /**
- * Create and show a input dialog for a number.
- *
- * @param options - The dialog setup options.
- *
- * @returns A promise that resolves with whether the dialog was accepted
+ * Namespace for input dialogs
  */
-export function getNumber(
-  options: InputDialog.INumberOptions
-): Promise<Dialog.IResult<number>> {
-  let dialog = new Dialog({
-    ...options,
-    body: new InputNumberDialog(options)
-  });
-  return dialog.launch();
-}
-
-/**
- * Create and show a input dialog for a choice.
- *
- * @param options - The dialog setup options.
- *
- * @returns A promise that resolves with whether the dialog was accepted
- */
-export function getItem(
-  options: InputDialog.IItemOptions
-): Promise<Dialog.IResult<string>> {
-  let dialog = new Dialog({
-    ...options,
-    body: new InputItemsDialog(options)
-  });
-  return dialog.launch();
-}
+export namespace InputDialog {
+  /**
+   * Common constructor options for input dialogs
+   */
+  export interface IOptions {
+    /**
+     * The top level text for the dialog.  Defaults to an empty string.
+     */
+    title: Dialog.Header;
 
-/**
- * Create and show a input dialog for a text.
- *
- * @param options - The dialog setup options.
- *
- * @returns A promise that resolves with whether the dialog was accepted
- */
-export function getText(
-  options: InputDialog.ITextOptions
-): Promise<Dialog.IResult<string>> {
-  let dialog = new Dialog({
-    ...options,
-    body: new InputTextDialog(options)
-  });
-  return dialog.launch();
-}
+    /**
+     * The host element for the dialog. Defaults to `document.body`.
+     */
+    host?: HTMLElement;
 
-export namespace InputDialog {
-  export interface IOptions<T>
-    extends Partial<
-      Pick<
-        Dialog.IOptions<T>,
-        Exclude<keyof Dialog.IOptions<T>, 'body' | 'buttons' | 'defaultButton'>
-      >
-    > {
     /**
      * Label of the requested input
      */
-    label: string;
+    label?: string;
+
+    /**
+     * An optional renderer for dialog items.  Defaults to a shared
+     * default renderer.
+     */
+    renderer?: Dialog.IRenderer;
   }
 
-  export interface INumberOptions extends IOptions<Number> {
+  /**
+   * Constructor options for boolean input dialogs
+   */
+  export interface IBooleanOptions extends IOptions {
+    /**
+     * Default value
+     */
+    value?: boolean;
+  }
+
+  /**
+   * Create and show a input dialog for a boolean.
+   *
+   * @param options - The dialog setup options.
+   *
+   * @returns A promise that resolves with whether the dialog was accepted
+   */
+  export function getBoolean(
+    options: IBooleanOptions
+  ): Promise<Dialog.IResult<boolean>> {
+    return showDialog({
+      ...options,
+      body: new InputBooleanDialog(options),
+      buttons: [Dialog.cancelButton(), Dialog.okButton()],
+      focusNodeSelector: 'input'
+    });
+  }
+
+  /**
+   * Constructor options for number input dialogs
+   */
+  export interface INumberOptions extends IOptions {
     /**
      * Default value
      */
     value?: number;
   }
 
-  export interface IItemOptions extends IOptions<string> {
+  /**
+   * Create and show a input dialog for a number.
+   *
+   * @param options - The dialog setup options.
+   *
+   * @returns A promise that resolves with whether the dialog was accepted
+   */
+  export function getNumber(
+    options: INumberOptions
+  ): Promise<Dialog.IResult<number>> {
+    return showDialog({
+      ...options,
+      body: new InputNumberDialog(options),
+      buttons: [Dialog.cancelButton(), Dialog.okButton()],
+      focusNodeSelector: 'input'
+    });
+  }
+
+  /**
+   * Constructor options for item selection input dialogs
+   */
+  export interface IItemOptions extends IOptions {
     /**
      * List of choices
      */
@@ -102,7 +119,28 @@ export namespace InputDialog {
     placeholder?: string;
   }
 
-  export interface ITextOptions extends IOptions<string> {
+  /**
+   * Create and show a input dialog for a choice.
+   *
+   * @param options - The dialog setup options.
+   *
+   * @returns A promise that resolves with whether the dialog was accepted
+   */
+  export function getItem(
+    options: IItemOptions
+  ): Promise<Dialog.IResult<string>> {
+    return showDialog({
+      ...options,
+      body: new InputItemsDialog(options),
+      buttons: [Dialog.cancelButton(), Dialog.okButton()],
+      focusNodeSelector: options.editable ? 'input' : 'select'
+    });
+  }
+
+  /**
+   * Constructor options for text input dialogs
+   */
+  export interface ITextOptions extends IOptions {
     /**
      * Default input text
      */
@@ -112,36 +150,85 @@ export namespace InputDialog {
      */
     placeholder?: string;
   }
+
+  /**
+   * Create and show a input dialog for a text.
+   *
+   * @param options - The dialog setup options.
+   *
+   * @returns A promise that resolves with whether the dialog was accepted
+   */
+  export function getText(
+    options: ITextOptions
+  ): Promise<Dialog.IResult<string>> {
+    return showDialog({
+      ...options,
+      body: new InputTextDialog(options),
+      buttons: [Dialog.cancelButton(), Dialog.okButton()],
+      focusNodeSelector: 'input'
+    });
+  }
 }
 
 /**
  * Base widget for input dialog body
  */
-class InputDialog<T> extends Widget implements Dialog.IBodyWidget<T> {
+class InputDialogBase<T> extends Widget implements Dialog.IBodyWidget<T> {
   /**
    * InputDialog constructor
    *
    * @param label Input field label
    */
-  constructor(label: string) {
+  constructor(label?: string) {
     super();
     this.addClass(INPUT_DIALOG_CLASS);
 
-    let labelElement = document.createElement('label');
-    labelElement.textContent = label;
+    if (label !== undefined) {
+      let labelElement = document.createElement('label');
+      labelElement.textContent = label;
 
-    // Initialize the node
-    this.node.appendChild(labelElement);
+      // Initialize the node
+      this.node.appendChild(labelElement);
+    }
   }
 
   /** Input HTML node */
   protected _input: HTMLInputElement;
 }
 
+/**
+ * Widget body for input boolean dialog
+ */
+class InputBooleanDialog extends InputDialogBase<boolean> {
+  /**
+   * InputBooleanDialog constructor
+   *
+   * @param options Constructor options
+   */
+  constructor(options: InputDialog.IBooleanOptions) {
+    super(options.label);
+
+    this._input = document.createElement('input');
+    this._input.classList.add('jp-mod-styled');
+    this._input.type = 'checkbox';
+    this._input.checked = options.value ? true : false;
+
+    // Initialize the node
+    this.node.appendChild(this._input);
+  }
+
+  /**
+   * Get the text specified by the user
+   */
+  getValue(): boolean {
+    return this._input.checked;
+  }
+}
+
 /**
  * Widget body for input number dialog
  */
-class InputNumberDialog extends InputDialog<number> {
+class InputNumberDialog extends InputDialogBase<number> {
   /**
    * InputNumberDialog constructor
    *
@@ -174,7 +261,7 @@ class InputNumberDialog extends InputDialog<number> {
 /**
  * Widget body for input text dialog
  */
-class InputTextDialog extends InputDialog<string> {
+class InputTextDialog extends InputDialogBase<string> {
   /**
    * InputTextDialog constructor
    *
@@ -206,7 +293,7 @@ class InputTextDialog extends InputDialog<string> {
 /**
  * Widget body for input list dialog
  */
-class InputItemsDialog extends InputDialog<string> {
+class InputItemsDialog extends InputDialogBase<string> {
   /**
    * InputItemsDialog constructor
    *

+ 9 - 2
packages/csvviewer-extension/src/index.ts

@@ -7,7 +7,11 @@ import {
   JupyterFrontEndPlugin
 } from '@jupyterlab/application';
 
-import { InstanceTracker, IThemeManager, Dialog } from '@jupyterlab/apputils';
+import {
+  InstanceTracker,
+  IThemeManager,
+  InputDialog
+} from '@jupyterlab/apputils';
 
 import { ISearchProviderRegistry } from '@jupyterlab/documentsearch';
 
@@ -64,7 +68,10 @@ function addMenuEntries(
   mainMenu.editMenu.goToLiners.add({
     tracker,
     goToLine: (widget: IDocumentWidget<CSVViewer>) => {
-      return Dialog.prompt<number>('Go to Line', 0).then(value => {
+      return InputDialog.getNumber({
+        title: 'Go to Line',
+        value: 0
+      }).then(value => {
         if (value.button.accept) {
           widget.content.goToLine(value.value);
         }

+ 231 - 127
tests/test-apputils/src/inputdialog.spec.ts

@@ -1,7 +1,7 @@
 // Copyright (c) Jupyter Development Team.
 // Distributed under the terms of the Modified BSD License.
 
-import { getItem, getText, getNumber } from '@jupyterlab/apputils';
+import { InputDialog } from '@jupyterlab/apputils';
 
 import {
   acceptDialog,
@@ -10,188 +10,292 @@ import {
 } from '@jupyterlab/testutils';
 
 describe('@jupyterlab/apputils', () => {
-  describe('getItem()', () => {
-    it('should accept at least two arguments', async () => {
-      const dialog = getItem({
-        label: 'list',
-        items: ['item1']
+  describe('InputDialog', () => {
+    describe('getBoolean()', () => {
+      it('should accept at least the title argument', async () => {
+        const dialog = InputDialog.getBoolean({
+          title: 'Check or not'
+        });
+
+        await dismissDialog();
+        expect((await dialog).button.accept).toBe(false);
       });
 
-      await dismissDialog();
-      expect((await dialog).button.accept).toBe(false);
-    });
+      it('should be false by default', async () => {
+        const dialog = InputDialog.getBoolean({
+          title: 'Check or not'
+        });
 
-    it('should accept options', async () => {
-      const dialog = getItem({
-        label: 'list',
-        items: ['item1', 'item2'],
-        current: 1,
-        editable: false,
-        title: 'Pick a choice',
-        placeholder: 'item'
-      });
+        await acceptDialog();
 
-      await acceptDialog();
+        const result = await dialog;
 
-      const result = await dialog;
+        expect(result.button.accept).toBe(true);
+        expect(result.value).toBe(false);
+      });
 
-      expect(result.button.accept).toBe(true);
-      expect(result.value).toBe('item2');
-    });
+      it('should accept options', async () => {
+        const dialog = InputDialog.getBoolean({
+          title: 'Check or not',
+          value: true
+        });
 
-    it('should be editable', async () => {
-      const node = document.createElement('div');
+        await acceptDialog();
 
-      document.body.appendChild(node);
+        const result = await dialog;
 
-      const prompt = getItem({
-        label: 'list',
-        items: ['item1', 'item2'],
-        title: 'Pick a choice',
-        placeholder: 'item',
-        editable: true,
-        host: node
+        expect(result.button.accept).toBe(true);
+        expect(result.value).toBe(true);
       });
 
-      await waitForDialog(node);
-      const body = node.getElementsByClassName('jp-Input-Dialog').item(0);
-      const input = body.getElementsByTagName('input').item(0);
-      input.value = 'item3';
+      it('should be editable', async () => {
+        const node = document.createElement('div');
 
-      await acceptDialog();
+        document.body.appendChild(node);
 
-      const result = await prompt;
+        const prompt = InputDialog.getBoolean({
+          title: 'Check or not',
+          host: node
+        });
 
-      expect(result.button.accept).toBe(true);
-      expect(result.value).toBe('item3');
-      document.body.removeChild(node);
-    });
-  });
+        await waitForDialog(node);
+        const body = node.getElementsByClassName('jp-Input-Dialog').item(0);
+        const input = body.getElementsByTagName('input').item(0);
+        input.checked = true;
 
-  describe('getText()', () => {
-    it('should accept at least one argument', async () => {
-      const dialog = getText({
-        label: 'text'
-      });
+        await acceptDialog();
+
+        const result = await prompt;
 
-      await dismissDialog();
-      expect((await dialog).button.accept).toBe(false);
+        expect(result.button.accept).toBe(true);
+        expect(result.value).toBe(true);
+        document.body.removeChild(node);
+      });
     });
 
-    it('should accept options', async () => {
-      const dialog = getText({
-        label: 'text',
-        title: 'Give a text',
-        placeholder: 'your text',
-        text: 'answer'
+    describe('getItem()', () => {
+      it('should accept at least two arguments', async () => {
+        const dialog = InputDialog.getItem({
+          title: 'list',
+          items: ['item1']
+        });
+
+        await dismissDialog();
+        expect((await dialog).button.accept).toBe(false);
       });
 
-      await acceptDialog();
+      it('should be the first item by default', async () => {
+        const dialog = InputDialog.getItem({
+          items: ['item1', 'item2'],
+          title: 'Pick a choice'
+        });
 
-      const result = await dialog;
+        await acceptDialog();
 
-      expect(result.button.accept).toBe(true);
-      expect(result.value).toBe('answer');
-    });
+        const result = await dialog;
+
+        expect(result.button.accept).toBe(true);
+        expect(result.value).toBe('item1');
+      });
+
+      it('should accept options', async () => {
+        const dialog = InputDialog.getItem({
+          label: 'list',
+          items: ['item1', 'item2'],
+          current: 1,
+          editable: false,
+          title: 'Pick a choice',
+          placeholder: 'item'
+        });
 
-    it('should be editable', async () => {
-      const node = document.createElement('div');
+        await acceptDialog();
 
-      document.body.appendChild(node);
+        const result = await dialog;
 
-      const prompt = getText({
-        label: 'text',
-        host: node
+        expect(result.button.accept).toBe(true);
+        expect(result.value).toBe('item2');
       });
 
-      await waitForDialog(node);
-      const body = node.getElementsByClassName('jp-Input-Dialog').item(0);
-      const input = body.getElementsByTagName('input').item(0);
-      input.value = 'my answer';
+      it('should be editable', async () => {
+        const node = document.createElement('div');
+
+        document.body.appendChild(node);
 
-      await acceptDialog();
+        const prompt = InputDialog.getItem({
+          label: 'list',
+          items: ['item1', 'item2'],
+          title: 'Pick a choice',
+          placeholder: 'item',
+          editable: true,
+          host: node
+        });
 
-      const result = await prompt;
+        await waitForDialog(node);
+        const body = node.getElementsByClassName('jp-Input-Dialog').item(0);
+        const input = body.getElementsByTagName('input').item(0);
+        input.value = 'item3';
 
-      expect(result.button.accept).toBe(true);
-      expect(result.value).toBe('my answer');
-      document.body.removeChild(node);
+        await acceptDialog();
+
+        const result = await prompt;
+
+        expect(result.button.accept).toBe(true);
+        expect(result.value).toBe('item3');
+        document.body.removeChild(node);
+      });
     });
-  });
 
-  describe('getNumber()', () => {
-    it('should accept at least one argument', async () => {
-      const dialog = getNumber({
-        label: 'number'
+    describe('getText()', () => {
+      it('should accept at least one argument', async () => {
+        const dialog = InputDialog.getText({
+          title: 'text'
+        });
+
+        await dismissDialog();
+        expect((await dialog).button.accept).toBe(false);
       });
 
-      await dismissDialog();
-      expect((await dialog).button.accept).toBe(false);
-    });
+      it('should be an empty string by default', async () => {
+        const dialog = InputDialog.getText({
+          title: 'Give a text'
+        });
 
-    it('should accept options', async () => {
-      const dialog = getNumber({
-        label: 'number',
-        title: 'Pick a number',
-        value: 10
+        await acceptDialog();
+
+        const result = await dialog;
+
+        expect(result.button.accept).toBe(true);
+        expect(result.value).toBe('');
       });
 
-      await acceptDialog();
+      it('should accept options', async () => {
+        const dialog = InputDialog.getText({
+          label: 'text',
+          title: 'Give a text',
+          placeholder: 'your text',
+          text: 'answer'
+        });
+
+        await acceptDialog();
 
-      const result = await dialog;
+        const result = await dialog;
 
-      expect(result.button.accept).toBe(true);
-      expect(result.value).toBe(10);
+        expect(result.button.accept).toBe(true);
+        expect(result.value).toBe('answer');
+      });
+
+      it('should be editable', async () => {
+        const node = document.createElement('div');
+
+        document.body.appendChild(node);
+
+        const prompt = InputDialog.getText({
+          title: 'text',
+          host: node
+        });
+
+        await waitForDialog(node);
+        const body = node.getElementsByClassName('jp-Input-Dialog').item(0);
+        const input = body.getElementsByTagName('input').item(0);
+        input.value = 'my answer';
+
+        await acceptDialog();
+
+        const result = await prompt;
+
+        expect(result.button.accept).toBe(true);
+        expect(result.value).toBe('my answer');
+        document.body.removeChild(node);
+      });
     });
 
-    it('should be editable', async () => {
-      const node = document.createElement('div');
+    describe('getNumber()', () => {
+      it('should accept at least one argument', async () => {
+        const dialog = InputDialog.getNumber({
+          title: 'number'
+        });
+
+        await dismissDialog();
+        expect((await dialog).button.accept).toBe(false);
+      });
+
+      it('should be 0 by default', async () => {
+        const dialog = InputDialog.getNumber({
+          title: 'Pick a number'
+        });
 
-      document.body.appendChild(node);
+        await acceptDialog();
 
-      const prompt = getNumber({
-        label: 'text',
-        title: 'Pick a number',
-        host: node
+        const result = await dialog;
+
+        expect(result.button.accept).toBe(true);
+        expect(result.value).toBe(0);
       });
 
-      await waitForDialog(node);
-      const body = node.getElementsByClassName('jp-Input-Dialog').item(0);
-      const input = body.getElementsByTagName('input').item(0);
-      input.value = '25';
+      it('should accept options', async () => {
+        const dialog = InputDialog.getNumber({
+          label: 'number',
+          title: 'Pick a number',
+          value: 10
+        });
 
-      await acceptDialog();
+        await acceptDialog();
 
-      const result = await prompt;
+        const result = await dialog;
 
-      expect(result.button.accept).toBe(true);
-      expect(result.value).toBe(25);
-      document.body.removeChild(node);
-    });
+        expect(result.button.accept).toBe(true);
+        expect(result.value).toBe(10);
+      });
+
+      it('should be editable', async () => {
+        const node = document.createElement('div');
+
+        document.body.appendChild(node);
+
+        const prompt = InputDialog.getNumber({
+          label: 'text',
+          title: 'Pick a number',
+          host: node
+        });
 
-    it('should return NaN if empty', async () => {
-      const node = document.createElement('div');
+        await waitForDialog(node);
+        const body = node.getElementsByClassName('jp-Input-Dialog').item(0);
+        const input = body.getElementsByTagName('input').item(0);
+        input.value = '25';
 
-      document.body.appendChild(node);
+        await acceptDialog();
 
-      const prompt = getNumber({
-        label: 'text',
-        title: 'Pick a number',
-        host: node
+        const result = await prompt;
+
+        expect(result.button.accept).toBe(true);
+        expect(result.value).toBe(25);
+        document.body.removeChild(node);
       });
 
-      await waitForDialog(node);
-      const body = node.getElementsByClassName('jp-Input-Dialog').item(0);
-      const input = body.getElementsByTagName('input').item(0);
-      input.value = '';
+      it('should return NaN if empty', async () => {
+        const node = document.createElement('div');
+
+        document.body.appendChild(node);
+
+        const prompt = InputDialog.getNumber({
+          label: 'text',
+          title: 'Pick a number',
+          host: node
+        });
 
-      await acceptDialog();
+        await waitForDialog(node);
+        const body = node.getElementsByClassName('jp-Input-Dialog').item(0);
+        const input = body.getElementsByTagName('input').item(0);
+        input.value = '';
 
-      const result = await prompt;
+        await acceptDialog();
 
-      expect(result.button.accept).toBe(true);
-      expect(result.value).toBe(Number.NaN);
-      document.body.removeChild(node);
+        const result = await prompt;
+
+        expect(result.button.accept).toBe(true);
+        expect(result.value).toBe(Number.NaN);
+        document.body.removeChild(node);
+      });
     });
   });
 });