You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by gr...@apache.org on 2018/06/23 03:09:13 UTC

[incubator-superset] branch dashboard-builder updated: [dashboard v2] add markdown tests (#5275)

This is an automated email from the ASF dual-hosted git repository.

graceguo pushed a commit to branch dashboard-builder
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git


The following commit(s) were added to refs/heads/dashboard-builder by this push:
     new 69621a9  [dashboard v2] add markdown tests (#5275)
69621a9 is described below

commit 69621a91cb95a83efd9a68f25cb732f635fa08dd
Author: Chris Williams <wi...@users.noreply.github.com>
AuthorDate: Fri Jun 22 20:09:07 2018 -0700

    [dashboard v2] add markdown tests (#5275)
    
    * [dashboard v2] add Markdown tests
    
    * [dashboard v2][mocks] fix markdown mock
---
 .../components/gridComponents/Markdown_spec.jsx    | 156 +++++++++++++++++++++
 .../dashboard/fixtures/mockDashboardLayout.js      |   6 +
 .../components/gridComponents/Markdown.jsx         |   4 +-
 3 files changed, 164 insertions(+), 2 deletions(-)

diff --git a/superset/assets/spec/javascripts/dashboard/components/gridComponents/Markdown_spec.jsx b/superset/assets/spec/javascripts/dashboard/components/gridComponents/Markdown_spec.jsx
new file mode 100644
index 0000000..ca71045
--- /dev/null
+++ b/superset/assets/spec/javascripts/dashboard/components/gridComponents/Markdown_spec.jsx
@@ -0,0 +1,156 @@
+import { Provider } from 'react-redux';
+import React from 'react';
+import { mount } from 'enzyme';
+import { describe, it } from 'mocha';
+import { expect } from 'chai';
+import sinon from 'sinon';
+import AceEditor from 'react-ace';
+import ReactMarkdown from 'react-markdown';
+
+import Markdown from '../../../../../src/dashboard/components/gridComponents/Markdown';
+import MarkdownModeDropdown from '../../../../../src/dashboard/components/menu/MarkdownModeDropdown';
+import DeleteComponentButton from '../../../../../src/dashboard/components/DeleteComponentButton';
+import DragDroppable from '../../../../../src/dashboard/components/dnd/DragDroppable';
+import WithPopoverMenu from '../../../../../src/dashboard/components/menu/WithPopoverMenu';
+import ResizableContainer from '../../../../../src/dashboard/components/resizable/ResizableContainer';
+
+import { mockStore } from '../../fixtures/mockStore';
+import { dashboardLayout as mockLayout } from '../../fixtures/mockDashboardLayout';
+import WithDragDropContext from '../../helpers/WithDragDropContext';
+
+describe('Markdown', () => {
+  const props = {
+    id: 'id',
+    parentId: 'parentId',
+    component: mockLayout.present.MARKDOWN_ID,
+    depth: 2,
+    parentComponent: mockLayout.present.ROW_ID,
+    index: 0,
+    editMode: false,
+    availableColumnCount: 12,
+    columnWidth: 50,
+    onResizeStart() {},
+    onResize() {},
+    onResizeStop() {},
+    handleComponentDrop() {},
+    updateComponents() {},
+    deleteComponent() {},
+  };
+
+  function setup(overrideProps) {
+    // We have to wrap provide DragDropContext for the underlying DragDroppable
+    // otherwise we cannot assert on DragDroppable children
+    const wrapper = mount(
+      <Provider store={mockStore}>
+        <WithDragDropContext>
+          <Markdown {...props} {...overrideProps} />
+        </WithDragDropContext>
+      </Provider>,
+    );
+    return wrapper;
+  }
+
+  it('should render a DragDroppable', () => {
+    const wrapper = setup();
+    expect(wrapper.find(DragDroppable)).to.have.length(1);
+  });
+
+  it('should render a WithPopoverMenu', () => {
+    const wrapper = setup();
+    expect(wrapper.find(WithPopoverMenu)).to.have.length(1);
+  });
+
+  it('should render a ResizableContainer', () => {
+    const wrapper = setup();
+    expect(wrapper.find(ResizableContainer)).to.have.length(1);
+  });
+
+  it('should only have an adjustableWidth if its parent is a Row', () => {
+    let wrapper = setup();
+    expect(wrapper.find(ResizableContainer).prop('adjustableWidth')).to.equal(
+      true,
+    );
+
+    wrapper = setup({ ...props, parentComponent: mockLayout.present.CHART_ID });
+    expect(wrapper.find(ResizableContainer).prop('adjustableWidth')).to.equal(
+      false,
+    );
+  });
+
+  it('should pass correct props to ResizableContainer', () => {
+    const wrapper = setup();
+    const resizableProps = wrapper.find(ResizableContainer).props();
+    expect(resizableProps.widthStep).to.equal(props.columnWidth);
+    expect(resizableProps.widthMultiple).to.equal(props.component.meta.width);
+    expect(resizableProps.heightMultiple).to.equal(props.component.meta.height);
+    expect(resizableProps.maxWidthMultiple).to.equal(
+      props.component.meta.width + props.availableColumnCount,
+    );
+  });
+
+  it('should render an Markdown when NOT focused', () => {
+    const wrapper = setup();
+    expect(wrapper.find(AceEditor)).to.have.length(0);
+    expect(wrapper.find(ReactMarkdown)).to.have.length(1);
+  });
+
+  it('should render an AceEditor when focused and editMode=true and editorMode=edit', () => {
+    const wrapper = setup({ editMode: true });
+    expect(wrapper.find(AceEditor)).to.have.length(0);
+    expect(wrapper.find(ReactMarkdown)).to.have.length(1);
+    wrapper.find(WithPopoverMenu).simulate('click'); // focus + edit
+    expect(wrapper.find(AceEditor)).to.have.length(1);
+    expect(wrapper.find(ReactMarkdown)).to.have.length(0);
+  });
+
+  it('should render a ReactMarkdown when focused and editMode=true and editorMode=preview', () => {
+    const wrapper = setup({ editMode: true });
+    wrapper.find(WithPopoverMenu).simulate('click'); // focus + edit
+    expect(wrapper.find(AceEditor)).to.have.length(1);
+    expect(wrapper.find(ReactMarkdown)).to.have.length(0);
+
+    // we can't call setState on Markdown bc it's not the root component, so call
+    // the mode dropdown onchange instead
+    const dropdown = wrapper.find(MarkdownModeDropdown);
+    dropdown.prop('onChange')('preview');
+
+    expect(wrapper.find(AceEditor)).to.have.length(0);
+    expect(wrapper.find(ReactMarkdown)).to.have.length(1);
+  });
+
+  it('should call updateComponents when editMode changes from edit => preview, and there are markdownSource changes', () => {
+    const updateComponents = sinon.spy();
+    const wrapper = setup({ editMode: true, updateComponents });
+    wrapper.find(WithPopoverMenu).simulate('click'); // focus + edit
+
+    // we can't call setState on Markdown bc it's not the root component, so call
+    // the mode dropdown onchange instead
+    const dropdown = wrapper.find(MarkdownModeDropdown);
+    dropdown.prop('onChange')('preview');
+    expect(updateComponents.callCount).to.equal(0);
+
+    dropdown.prop('onChange')('edit');
+    // because we can't call setState on Markdown, change it through the editor
+    // then go back to preview mode to invoke updateComponents
+    const editor = wrapper.find(AceEditor);
+    editor.prop('onChange')('new markdown!');
+    dropdown.prop('onChange')('preview');
+    expect(updateComponents.callCount).to.equal(1);
+  });
+
+  it('should render a DeleteComponentButton when focused in editMode', () => {
+    const wrapper = setup({ editMode: true });
+    wrapper.find(WithPopoverMenu).simulate('click'); // focus
+
+    expect(wrapper.find(DeleteComponentButton)).to.have.length(1);
+  });
+
+  it('should call deleteComponent when deleted', () => {
+    const deleteComponent = sinon.spy();
+    const wrapper = setup({ editMode: true, deleteComponent });
+    wrapper.find(WithPopoverMenu).simulate('click'); // focus
+    wrapper.find(DeleteComponentButton).simulate('click');
+
+    expect(deleteComponent.callCount).to.equal(1);
+  });
+});
diff --git a/superset/assets/spec/javascripts/dashboard/fixtures/mockDashboardLayout.js b/superset/assets/spec/javascripts/dashboard/fixtures/mockDashboardLayout.js
index 865af0a..7327d69 100644
--- a/superset/assets/spec/javascripts/dashboard/fixtures/mockDashboardLayout.js
+++ b/superset/assets/spec/javascripts/dashboard/fixtures/mockDashboardLayout.js
@@ -7,6 +7,7 @@ import {
   CHART_TYPE,
   ROW_TYPE,
   COLUMN_TYPE,
+  MARKDOWN_TYPE,
 } from '../../../../src/dashboard/util/componentTypes';
 
 import {
@@ -67,6 +68,11 @@ export const dashboardLayout = {
         chartName: 'Mock chart name',
       },
     },
+
+    MARKDOWN_ID: {
+      ...newComponentFactory(MARKDOWN_TYPE),
+      id: 'MARKDOWN_ID',
+    },
   },
   future: [],
 };
diff --git a/superset/assets/src/dashboard/components/gridComponents/Markdown.jsx b/superset/assets/src/dashboard/components/gridComponents/Markdown.jsx
index bd639e7..aba76ca 100644
--- a/superset/assets/src/dashboard/components/gridComponents/Markdown.jsx
+++ b/superset/assets/src/dashboard/components/gridComponents/Markdown.jsx
@@ -163,7 +163,7 @@ class Markdown extends React.PureComponent {
   }
 
   render() {
-    const { isFocused } = this.state;
+    const { isFocused, editorMode } = this.state;
 
     const {
       component,
@@ -185,7 +185,7 @@ class Markdown extends React.PureComponent {
         ? parentComponent.meta.width || GRID_MIN_COLUMN_COUNT
         : component.meta.width || GRID_MIN_COLUMN_COUNT;
 
-    const isEditing = this.state.editorMode === 'edit';
+    const isEditing = editorMode === 'edit';
 
     return (
       <DragDroppable