Write Test for cardDetailContents (#884)
* LETS WRITE SOME TESTS WOOHOO!!! * fix up testing * update snapshot * use mockDOM * fix linting * use querySelector Co-authored-by: Scott Bishel <scott.bishel@mattermost.com>
This commit is contained in:
parent
904dfc2158
commit
cdc72c31f8
8 changed files with 1595 additions and 54 deletions
|
@ -0,0 +1,979 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`components/cardDetail/cardDetailContents should match snapshot 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="octo-content CardDetailContents"
|
||||
>
|
||||
<div
|
||||
class="octo-block"
|
||||
>
|
||||
<div
|
||||
class="octo-block-margin"
|
||||
/>
|
||||
<div
|
||||
class="MarkdownEditor octo-editor "
|
||||
>
|
||||
<div
|
||||
class="octo-editor-preview octo-placeholder"
|
||||
>
|
||||
<p>
|
||||
Add a description...
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="octo-editor-active Editor"
|
||||
style="visibility: hidden; position: absolute; top: 0px; left: 0px;"
|
||||
>
|
||||
<div
|
||||
id="test-id-wrapper"
|
||||
>
|
||||
<textarea
|
||||
id="test-id"
|
||||
style="display: none;"
|
||||
/>
|
||||
<div
|
||||
class="EasyMDEContainer"
|
||||
>
|
||||
<div
|
||||
class="CodeMirror cm-s-easymde CodeMirror-wrap CodeMirror-focused"
|
||||
>
|
||||
<div
|
||||
style="overflow: hidden; position: relative; width: 3px; height: 0px;"
|
||||
>
|
||||
<textarea
|
||||
autocapitalize="off"
|
||||
autocorrect="off"
|
||||
spellcheck="false"
|
||||
style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="CodeMirror-vscrollbar"
|
||||
cm-not-content="true"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
style="min-width: 1px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="CodeMirror-hscrollbar"
|
||||
cm-not-content="true"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
style="height: 100%; min-height: 1px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="CodeMirror-scrollbar-filler"
|
||||
cm-not-content="true"
|
||||
/>
|
||||
<div
|
||||
class="CodeMirror-gutter-filler"
|
||||
cm-not-content="true"
|
||||
/>
|
||||
<div
|
||||
class="CodeMirror-scroll"
|
||||
style="min-height: 10px;"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
class="CodeMirror-sizer"
|
||||
style="margin-left: 0px;"
|
||||
>
|
||||
<div
|
||||
style="position: relative;"
|
||||
>
|
||||
<div
|
||||
class="CodeMirror-lines"
|
||||
role="presentation"
|
||||
>
|
||||
<div
|
||||
role="presentation"
|
||||
style="position: relative; outline: none;"
|
||||
>
|
||||
<div
|
||||
class="CodeMirror-measure"
|
||||
>
|
||||
<pre
|
||||
class="CodeMirror-line-like"
|
||||
>
|
||||
<span>
|
||||
xxxxxxxxxx
|
||||
</span>
|
||||
</pre>
|
||||
</div>
|
||||
<div
|
||||
class="CodeMirror-measure"
|
||||
/>
|
||||
<div
|
||||
style="position: relative; z-index: 1;"
|
||||
/>
|
||||
<div
|
||||
class="CodeMirror-cursors"
|
||||
/>
|
||||
<div
|
||||
class="CodeMirror-code"
|
||||
role="presentation"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style="position: absolute; height: 50px; width: 1px;"
|
||||
/>
|
||||
<div
|
||||
class="CodeMirror-gutters"
|
||||
style="display: none;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="editor-preview-side editor-preview"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components/cardDetail/cardDetailContents should match snapshot after drag and drop event 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="octo-content"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="width: 94%; height: 10px; margin-left: 48px;"
|
||||
/>
|
||||
<div
|
||||
class="rowContents"
|
||||
>
|
||||
<div
|
||||
class="ContentBlock octo-block"
|
||||
>
|
||||
<div
|
||||
class="octo-block-margin"
|
||||
>
|
||||
<div
|
||||
class="MenuWrapper"
|
||||
>
|
||||
<div
|
||||
class="Button IconButton"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-dots-horizontal OptionsIcon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="dnd-handle"
|
||||
draggable="true"
|
||||
>
|
||||
<svg
|
||||
class="GripIcon Icon"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0 0h24v24H0V0z"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="flex: 0 0 auto; height: 100%;"
|
||||
/>
|
||||
<div
|
||||
class="DividerElement"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="width: 94%; height: 10px; margin-left: 48px;"
|
||||
/>
|
||||
<div
|
||||
style="display: flex;"
|
||||
>
|
||||
<div
|
||||
class="rowContents"
|
||||
style="width: 50%;"
|
||||
>
|
||||
<div
|
||||
class="ContentBlock octo-block"
|
||||
>
|
||||
<div
|
||||
class="octo-block-margin"
|
||||
>
|
||||
<div
|
||||
class="MenuWrapper"
|
||||
>
|
||||
<div
|
||||
class="Button IconButton"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-dots-horizontal OptionsIcon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="dnd-handle"
|
||||
draggable="true"
|
||||
>
|
||||
<svg
|
||||
class="GripIcon Icon"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0 0h24v24H0V0z"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="flex: 0 0 auto; height: 100%;"
|
||||
/>
|
||||
<div
|
||||
class="DividerElement"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="rowContents"
|
||||
style="width: 50%;"
|
||||
>
|
||||
<div
|
||||
class="ContentBlock octo-block"
|
||||
>
|
||||
<div
|
||||
class="octo-block-margin"
|
||||
>
|
||||
<div
|
||||
class="MenuWrapper"
|
||||
>
|
||||
<div
|
||||
class="Button IconButton"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-dots-horizontal OptionsIcon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="dnd-handle"
|
||||
draggable="true"
|
||||
>
|
||||
<svg
|
||||
class="GripIcon Icon"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0 0h24v24H0V0z"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="DividerElement"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="width: 94%; height: 10px; margin-left: 48px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components/cardDetail/cardDetailContents should match snapshot after drag and drop event 2 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="octo-content"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="width: 94%; height: 10px; margin-left: 48px;"
|
||||
/>
|
||||
<div
|
||||
class="rowContents"
|
||||
>
|
||||
<div
|
||||
class="ContentBlock octo-block"
|
||||
>
|
||||
<div
|
||||
class="octo-block-margin"
|
||||
>
|
||||
<div
|
||||
class="MenuWrapper"
|
||||
>
|
||||
<div
|
||||
class="Button IconButton"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-dots-horizontal OptionsIcon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="dnd-handle"
|
||||
draggable="true"
|
||||
>
|
||||
<svg
|
||||
class="GripIcon Icon"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0 0h24v24H0V0z"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="flex: 0 0 auto; height: 100%;"
|
||||
/>
|
||||
<div
|
||||
class="DividerElement"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="width: 94%; height: 10px; margin-left: 48px;"
|
||||
/>
|
||||
<div
|
||||
class="rowContents"
|
||||
>
|
||||
<div
|
||||
class="ContentBlock octo-block"
|
||||
>
|
||||
<div
|
||||
class="octo-block-margin"
|
||||
>
|
||||
<div
|
||||
class="MenuWrapper"
|
||||
>
|
||||
<div
|
||||
class="Button IconButton"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-dots-horizontal OptionsIcon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="dnd-handle"
|
||||
draggable="true"
|
||||
>
|
||||
<svg
|
||||
class="GripIcon Icon"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0 0h24v24H0V0z"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="flex: 0 0 auto; height: 100%;"
|
||||
/>
|
||||
<div
|
||||
class="DividerElement"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="width: 94%; height: 10px; margin-left: 48px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components/cardDetail/cardDetailContents should match snapshot after drag and drop event 3 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="octo-content"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="width: 94%; height: 10px; margin-left: 48px;"
|
||||
/>
|
||||
<div
|
||||
class="rowContents"
|
||||
>
|
||||
<div
|
||||
class="ContentBlock octo-block"
|
||||
>
|
||||
<div
|
||||
class="octo-block-margin"
|
||||
>
|
||||
<div
|
||||
class="MenuWrapper"
|
||||
>
|
||||
<div
|
||||
class="Button IconButton"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-dots-horizontal OptionsIcon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="dnd-handle"
|
||||
draggable="true"
|
||||
>
|
||||
<svg
|
||||
class="GripIcon Icon"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0 0h24v24H0V0z"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="flex: 0 0 auto; height: 100%;"
|
||||
/>
|
||||
<div
|
||||
class="DividerElement"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="width: 94%; height: 10px; margin-left: 48px;"
|
||||
/>
|
||||
<div
|
||||
class="rowContents"
|
||||
>
|
||||
<div
|
||||
class="ContentBlock octo-block"
|
||||
>
|
||||
<div
|
||||
class="octo-block-margin"
|
||||
>
|
||||
<div
|
||||
class="MenuWrapper"
|
||||
>
|
||||
<div
|
||||
class="Button IconButton"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-dots-horizontal OptionsIcon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="dnd-handle"
|
||||
draggable="true"
|
||||
>
|
||||
<svg
|
||||
class="GripIcon Icon"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0 0h24v24H0V0z"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="flex: 0 0 auto; height: 100%;"
|
||||
/>
|
||||
<div
|
||||
class="DividerElement"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="width: 94%; height: 10px; margin-left: 48px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components/cardDetail/cardDetailContents should match snapshot after onBlur triggers 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="octo-content CardDetailContents"
|
||||
>
|
||||
<div
|
||||
class="octo-block"
|
||||
>
|
||||
<div
|
||||
class="octo-block-margin"
|
||||
/>
|
||||
<div
|
||||
class="MarkdownEditor octo-editor active"
|
||||
>
|
||||
<div
|
||||
class="octo-editor-preview octo-placeholder"
|
||||
style="display: none;"
|
||||
>
|
||||
<p>
|
||||
Add a description...
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="octo-editor-active Editor"
|
||||
style=""
|
||||
>
|
||||
<div
|
||||
id="test-id-wrapper"
|
||||
>
|
||||
<textarea
|
||||
id="test-id"
|
||||
style="display: none;"
|
||||
/>
|
||||
<div
|
||||
class="EasyMDEContainer"
|
||||
>
|
||||
<div
|
||||
class="CodeMirror cm-s-easymde CodeMirror-wrap CodeMirror-focused"
|
||||
>
|
||||
<div
|
||||
style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 0px;"
|
||||
>
|
||||
<textarea
|
||||
autocapitalize="off"
|
||||
autocorrect="off"
|
||||
spellcheck="false"
|
||||
style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="CodeMirror-vscrollbar"
|
||||
cm-not-content="true"
|
||||
style="display: block; bottom: 0px;"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
style="min-width: 1px; height: 52px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="CodeMirror-hscrollbar"
|
||||
cm-not-content="true"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
style="height: 100%; min-height: 1px; width: 0px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="CodeMirror-scrollbar-filler"
|
||||
cm-not-content="true"
|
||||
/>
|
||||
<div
|
||||
class="CodeMirror-gutter-filler"
|
||||
cm-not-content="true"
|
||||
/>
|
||||
<div
|
||||
class="CodeMirror-scroll"
|
||||
style="min-height: 10px;"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
class="CodeMirror-sizer"
|
||||
style="margin-left: 0px; padding-right: 0px; padding-bottom: 0px;"
|
||||
>
|
||||
<div
|
||||
style="position: relative;"
|
||||
>
|
||||
<div
|
||||
class="CodeMirror-lines"
|
||||
role="presentation"
|
||||
>
|
||||
<div
|
||||
role="presentation"
|
||||
style="position: relative; outline: none;"
|
||||
>
|
||||
<div
|
||||
class="CodeMirror-measure"
|
||||
/>
|
||||
<div
|
||||
class="CodeMirror-measure"
|
||||
>
|
||||
<pre
|
||||
class="CodeMirror-line"
|
||||
role="presentation"
|
||||
>
|
||||
<span
|
||||
role="presentation"
|
||||
style="padding-right: .1px;"
|
||||
>
|
||||
test123
|
||||
</span>
|
||||
</pre>
|
||||
</div>
|
||||
<div
|
||||
style="position: relative; z-index: 1;"
|
||||
/>
|
||||
<div
|
||||
class="CodeMirror-cursors"
|
||||
/>
|
||||
<div
|
||||
class="CodeMirror-code"
|
||||
role="presentation"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style="position: absolute; height: 50px; width: 1px; border-bottom: 0px solid transparent;"
|
||||
/>
|
||||
<div
|
||||
class="CodeMirror-gutters"
|
||||
style="display: none;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="editor-preview-side editor-preview"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components/cardDetail/cardDetailContents should match snapshot with contents array 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="octo-content"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="width: 94%; height: 10px; margin-left: 48px;"
|
||||
/>
|
||||
<div
|
||||
class="rowContents"
|
||||
>
|
||||
<div
|
||||
class="ContentBlock octo-block"
|
||||
>
|
||||
<div
|
||||
class="octo-block-margin"
|
||||
>
|
||||
<div
|
||||
class="MenuWrapper"
|
||||
>
|
||||
<div
|
||||
class="Button IconButton"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-dots-horizontal OptionsIcon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="dnd-handle"
|
||||
draggable="true"
|
||||
>
|
||||
<svg
|
||||
class="GripIcon Icon"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0 0h24v24H0V0z"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="flex: 0 0 auto; height: 100%;"
|
||||
/>
|
||||
<div
|
||||
class="DividerElement"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="width: 94%; height: 10px; margin-left: 48px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components/cardDetail/cardDetailContents should match snapshot with contents array that has array inside it 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="octo-content"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="width: 94%; height: 10px; margin-left: 48px;"
|
||||
/>
|
||||
<div
|
||||
class="rowContents"
|
||||
>
|
||||
<div
|
||||
class="ContentBlock octo-block"
|
||||
>
|
||||
<div
|
||||
class="octo-block-margin"
|
||||
>
|
||||
<div
|
||||
class="MenuWrapper"
|
||||
>
|
||||
<div
|
||||
class="Button IconButton"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-dots-horizontal OptionsIcon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="dnd-handle"
|
||||
draggable="true"
|
||||
>
|
||||
<svg
|
||||
class="GripIcon Icon"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0 0h24v24H0V0z"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="flex: 0 0 auto; height: 100%;"
|
||||
/>
|
||||
<div
|
||||
class="DividerElement"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="width: 94%; height: 10px; margin-left: 48px;"
|
||||
/>
|
||||
<div
|
||||
style="display: flex;"
|
||||
>
|
||||
<div
|
||||
class="rowContents"
|
||||
style="width: 50%;"
|
||||
>
|
||||
<div
|
||||
class="ContentBlock octo-block"
|
||||
>
|
||||
<div
|
||||
class="octo-block-margin"
|
||||
>
|
||||
<div
|
||||
class="MenuWrapper"
|
||||
>
|
||||
<div
|
||||
class="Button IconButton"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-dots-horizontal OptionsIcon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="dnd-handle"
|
||||
draggable="true"
|
||||
>
|
||||
<svg
|
||||
class="GripIcon Icon"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0 0h24v24H0V0z"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="flex: 0 0 auto; height: 100%;"
|
||||
/>
|
||||
<div
|
||||
class="DividerElement"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="rowContents"
|
||||
style="width: 50%;"
|
||||
>
|
||||
<div
|
||||
class="ContentBlock octo-block"
|
||||
>
|
||||
<div
|
||||
class="octo-block-margin"
|
||||
>
|
||||
<div
|
||||
class="MenuWrapper"
|
||||
>
|
||||
<div
|
||||
class="Button IconButton"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-dots-horizontal OptionsIcon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="dnd-handle"
|
||||
draggable="true"
|
||||
>
|
||||
<svg
|
||||
class="GripIcon Icon"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0 0h24v24H0V0z"
|
||||
fill="none"
|
||||
/>
|
||||
<path
|
||||
d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="DividerElement"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="addToRow "
|
||||
style="width: 94%; height: 10px; margin-left: 48px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
248
webapp/src/components/cardDetail/cardDetailContents.test.tsx
Normal file
248
webapp/src/components/cardDetail/cardDetailContents.test.tsx
Normal file
|
@ -0,0 +1,248 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React from 'react'
|
||||
|
||||
import {fireEvent, render} from '@testing-library/react'
|
||||
|
||||
import {IntlProvider} from 'react-intl'
|
||||
import {act} from 'react-dom/test-utils'
|
||||
|
||||
import {DndProvider} from 'react-dnd'
|
||||
import {HTML5Backend} from 'react-dnd-html5-backend'
|
||||
|
||||
import {TestBlockFactory} from '../../test/testBlockFactory'
|
||||
|
||||
import {mockDOM} from '../../testUtils'
|
||||
|
||||
import CardDetailContents from './cardDetailContents'
|
||||
|
||||
const wrapProviders = (children: any) => {
|
||||
return (
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<IntlProvider locale='en'>{children}</IntlProvider>
|
||||
</DndProvider>
|
||||
)
|
||||
}
|
||||
|
||||
global.fetch = jest.fn()
|
||||
|
||||
beforeAll(() => {
|
||||
mockDOM()
|
||||
})
|
||||
|
||||
describe('components/cardDetail/cardDetailContents', () => {
|
||||
const board = TestBlockFactory.createBoard()
|
||||
board.fields.cardProperties = [
|
||||
{
|
||||
id: 'property_id_1',
|
||||
name: 'Owner',
|
||||
type: 'select',
|
||||
options: [
|
||||
{
|
||||
color: 'propColorDefault',
|
||||
id: 'property_value_id_1',
|
||||
value: 'Jean-Luc Picard',
|
||||
},
|
||||
{
|
||||
color: 'propColorDefault',
|
||||
id: 'property_value_id_2',
|
||||
value: 'William Riker',
|
||||
},
|
||||
{
|
||||
color: 'propColorDefault',
|
||||
id: 'property_value_id_3',
|
||||
value: 'Deanna Troi',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const card = TestBlockFactory.createCard(board)
|
||||
|
||||
test('should match snapshot', async () => {
|
||||
const component = wrapProviders((
|
||||
<CardDetailContents
|
||||
id='test-id'
|
||||
card={card}
|
||||
contents={[]}
|
||||
readonly={false}
|
||||
/>
|
||||
))
|
||||
|
||||
let container: Element | undefined
|
||||
await act(async () => {
|
||||
const result = render(component)
|
||||
container = result.container
|
||||
})
|
||||
expect(container).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('should match snapshot with contents array', async () => {
|
||||
const contents = [TestBlockFactory.createDivider(card)]
|
||||
const component = wrapProviders((
|
||||
<CardDetailContents
|
||||
id='test-id'
|
||||
card={card}
|
||||
contents={contents}
|
||||
readonly={false}
|
||||
/>
|
||||
))
|
||||
|
||||
let container: Element | undefined
|
||||
await act(async () => {
|
||||
const result = render(component)
|
||||
container = result.container
|
||||
})
|
||||
expect(container).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('should match snapshot after onBlur triggers', async () => {
|
||||
const component = wrapProviders((
|
||||
<CardDetailContents
|
||||
id='test-id'
|
||||
card={card}
|
||||
contents={[]}
|
||||
readonly={false}
|
||||
/>
|
||||
))
|
||||
|
||||
let container: Element | undefined
|
||||
await act(async () => {
|
||||
const result = render(component)
|
||||
container = result.container
|
||||
})
|
||||
const markdownEditorField = container!.querySelector('.octo-editor-preview.octo-placeholder')
|
||||
expect(markdownEditorField).toBeDefined()
|
||||
fireEvent.click(markdownEditorField!)
|
||||
|
||||
const onFocusEvent = new FocusEvent('focus', {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
})
|
||||
|
||||
const onBlurEvent = new FocusEvent('blur', {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
})
|
||||
|
||||
const textareaContainer = container!.querySelectorAll('.CodeMirror.cm-s-easymde.CodeMirror-wrap')
|
||||
const textarea = textareaContainer[textareaContainer.length - 1].querySelector('textarea')
|
||||
|
||||
await act(async () => {
|
||||
textarea!.dispatchEvent(onFocusEvent)
|
||||
fireEvent.input(textarea!, {target: {value: 'test123'}})
|
||||
fireEvent.keyPress(textarea!, {key: 'Escape', code: 'Escape'})
|
||||
textarea!.dispatchEvent(onBlurEvent)
|
||||
})
|
||||
|
||||
expect(container).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('should match snapshot with contents array that has array inside it', async () => {
|
||||
const contents = [TestBlockFactory.createDivider(card), [TestBlockFactory.createDivider(card), TestBlockFactory.createDivider(card)]]
|
||||
const component = wrapProviders((
|
||||
<CardDetailContents
|
||||
id='test-id'
|
||||
card={card}
|
||||
contents={contents}
|
||||
readonly={false}
|
||||
/>
|
||||
))
|
||||
|
||||
let container: Element | undefined
|
||||
await act(async () => {
|
||||
const result = render(component)
|
||||
container = result.container
|
||||
})
|
||||
expect(container).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('should match snapshot after drag and drop event', async () => {
|
||||
const contents = [TestBlockFactory.createDivider(card), [TestBlockFactory.createDivider(card), TestBlockFactory.createDivider(card)]]
|
||||
card.fields.contentOrder = contents.map((content) => (Array.isArray(content) ? content.map((c) => c.id) : (content as any).id))
|
||||
const component = wrapProviders((
|
||||
<CardDetailContents
|
||||
id='test-id'
|
||||
card={card}
|
||||
contents={contents}
|
||||
readonly={false}
|
||||
/>
|
||||
))
|
||||
|
||||
let container: Element | undefined
|
||||
await act(async () => {
|
||||
const result = render(component)
|
||||
container = result.container
|
||||
})
|
||||
|
||||
const drag = container!.querySelectorAll('.dnd-handle')[0]
|
||||
const drop = container!.querySelectorAll('.addToRow')[4]
|
||||
|
||||
fireEvent.dragStart(drag)
|
||||
fireEvent.dragEnter(drop)
|
||||
fireEvent.dragOver(drop)
|
||||
fireEvent.drop(drop)
|
||||
|
||||
expect(container).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('should match snapshot after drag and drop event 2', async () => {
|
||||
const contents = [TestBlockFactory.createDivider(card), TestBlockFactory.createDivider(card)]
|
||||
card.fields.contentOrder = contents.map((content) => (Array.isArray(content) ? content.map((c) => c.id) : (content as any).id))
|
||||
const component = wrapProviders((
|
||||
<CardDetailContents
|
||||
id='test-id'
|
||||
card={card}
|
||||
contents={contents}
|
||||
readonly={false}
|
||||
/>
|
||||
))
|
||||
|
||||
let container: Element | undefined
|
||||
await act(async () => {
|
||||
const result = render(component)
|
||||
container = result.container
|
||||
})
|
||||
|
||||
const drag = container!.querySelectorAll('.dnd-handle')[0]
|
||||
const drop = container!.querySelectorAll('.addToRow')[4]
|
||||
|
||||
fireEvent.dragStart(drag)
|
||||
fireEvent.dragEnter(drop)
|
||||
fireEvent.dragOver(drop)
|
||||
fireEvent.drop(drop)
|
||||
|
||||
expect(container).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('should match snapshot after drag and drop event 3', async () => {
|
||||
const contents = [TestBlockFactory.createDivider(card), TestBlockFactory.createDivider(card)]
|
||||
card.fields.contentOrder = contents.map((content) => (Array.isArray(content) ? content.map((c) => c.id) : (content as any).id))
|
||||
const component = wrapProviders((
|
||||
<CardDetailContents
|
||||
id='test-id'
|
||||
card={card}
|
||||
contents={contents}
|
||||
readonly={false}
|
||||
/>
|
||||
))
|
||||
|
||||
let container: Element | undefined
|
||||
await act(async () => {
|
||||
const result = render(component)
|
||||
container = result.container
|
||||
})
|
||||
|
||||
const drag = container!.querySelectorAll('.dnd-handle')[1]
|
||||
const drop = container!.querySelectorAll('.addToRow')[2]
|
||||
|
||||
fireEvent.dragStart(drag)
|
||||
fireEvent.dragEnter(drop)
|
||||
fireEvent.dragOver(drop)
|
||||
fireEvent.drop(drop)
|
||||
|
||||
expect(container).toMatchSnapshot()
|
||||
})
|
||||
})
|
|
@ -12,9 +12,12 @@ import {useSortableWithGrip} from '../../hooks/sortable'
|
|||
import ContentBlock from '../contentBlock'
|
||||
import {MarkdownEditor} from '../markdownEditor'
|
||||
|
||||
import {dragAndDropRearrange} from './cardDetailContentsUtility'
|
||||
|
||||
export type Position = 'left' | 'right' | 'above' | 'below' | 'aboveRow' | 'belowRow'
|
||||
|
||||
type Props = {
|
||||
id?: string
|
||||
card: Card
|
||||
contents: Array<ContentBlockType|ContentBlockType[]>
|
||||
readonly: boolean
|
||||
|
@ -51,59 +54,20 @@ function moveBlock(card: Card, srcBlock: IContentBlockWithCords, dstBlock: ICont
|
|||
const dstBlockId = dstBlock.block.id
|
||||
|
||||
const srcBlockX = srcBlock.cords.x
|
||||
let dstBlockX = dstBlock.cords.x
|
||||
const dstBlockX = dstBlock.cords.x
|
||||
|
||||
const srcBlockY = (srcBlock.cords.y || srcBlock.cords.y === 0) && (srcBlock.cords.y > -1) ? srcBlock.cords.y : -1
|
||||
let dstBlockY = (dstBlock.cords.y || dstBlock.cords.y === 0) && (dstBlock.cords.y > -1) ? dstBlock.cords.y : -1
|
||||
const dstBlockY = (dstBlock.cords.y || dstBlock.cords.y === 0) && (dstBlock.cords.y > -1) ? dstBlock.cords.y : -1
|
||||
|
||||
if (srcBlockId === dstBlockId) {
|
||||
return
|
||||
}
|
||||
|
||||
// Delete Src Block
|
||||
if (srcBlockY > -1) {
|
||||
(contentOrder[srcBlockX] as string[]).splice(srcBlockY, 1)
|
||||
|
||||
if (contentOrder[srcBlockX].length === 1 && srcBlockX !== dstBlockX) {
|
||||
contentOrder.splice(srcBlockX, 1, contentOrder[srcBlockX][0])
|
||||
}
|
||||
} else {
|
||||
contentOrder.splice(srcBlockX, 1)
|
||||
|
||||
if (dstBlockX > srcBlockX) {
|
||||
dstBlockX -= 1
|
||||
}
|
||||
}
|
||||
|
||||
if (moveTo === 'right') {
|
||||
if (dstBlockY > -1) {
|
||||
if (dstBlockX === srcBlockX && dstBlockY > srcBlockY) {
|
||||
dstBlockY -= 1
|
||||
}
|
||||
|
||||
(contentOrder[dstBlockX] as string[]).splice(dstBlockY + 1, 0, srcBlockId)
|
||||
} else {
|
||||
contentOrder.splice(dstBlockX, 1, [dstBlockId, srcBlockId])
|
||||
}
|
||||
} else if (moveTo === 'left') {
|
||||
if (dstBlockY > -1) {
|
||||
if (dstBlockX === srcBlockX && dstBlockY > srcBlockY) {
|
||||
dstBlockY -= 1
|
||||
}
|
||||
|
||||
(contentOrder[dstBlockX] as string[]).splice(dstBlockY, 0, srcBlockId)
|
||||
} else {
|
||||
contentOrder.splice(dstBlockX, 1, [srcBlockId, dstBlockId])
|
||||
}
|
||||
} else if (moveTo === 'aboveRow') {
|
||||
contentOrder.splice(dstBlockX, 0, srcBlockId)
|
||||
} else if (moveTo === 'belowRow') {
|
||||
contentOrder.splice(dstBlockX + 1, 0, srcBlockId)
|
||||
}
|
||||
const newContentOrder = dragAndDropRearrange({contentOrder, srcBlockId, srcBlockX, srcBlockY, dstBlockId, dstBlockX, dstBlockY, moveTo})
|
||||
|
||||
mutator.performAsUndoGroup(async () => {
|
||||
const description = intl.formatMessage({id: 'CardDetail.moveContent', defaultMessage: 'move card content'})
|
||||
await mutator.changeCardContentOrder(card, contentOrder, description)
|
||||
await mutator.changeCardContentOrder(card, newContentOrder, description)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -185,11 +149,8 @@ const ContentBlockWithDragAndDrop = (props: ContentBlockWithDragAndDropProps) =>
|
|||
|
||||
const CardDetailContents = React.memo((props: Props) => {
|
||||
const intl = useIntl()
|
||||
const {contents, card} = props
|
||||
if (!contents) {
|
||||
return null
|
||||
}
|
||||
if (contents.length > 0) {
|
||||
const {contents, card, id} = props
|
||||
if (contents.length) {
|
||||
return (
|
||||
<div className='octo-content'>
|
||||
{contents.map((block, x) =>
|
||||
|
@ -214,6 +175,7 @@ const CardDetailContents = React.memo((props: Props) => {
|
|||
<div className='octo-block-margin'/>
|
||||
{!props.readonly &&
|
||||
<MarkdownEditor
|
||||
id={id}
|
||||
text=''
|
||||
placeholderText='Add a description...'
|
||||
onBlur={(text) => {
|
||||
|
|
|
@ -0,0 +1,271 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {dragAndDropRearrange} from './cardDetailContentsUtility'
|
||||
import {Position} from './cardDetailContents'
|
||||
|
||||
describe('components/cardDetail/cardDetailContentsUtility', () => {
|
||||
test('Testing moving first item in the row to the end', () => {
|
||||
const data = {
|
||||
contentOrder: [
|
||||
['1', '2', '3'],
|
||||
],
|
||||
srcBlockId: '1',
|
||||
srcBlockX: 0,
|
||||
srcBlockY: 0,
|
||||
dstBlockX: 0,
|
||||
dstBlockY: 2,
|
||||
dstBlockId: '3',
|
||||
moveTo: 'right' as Position,
|
||||
}
|
||||
|
||||
const result = dragAndDropRearrange(data)
|
||||
const expected = [
|
||||
['2', '3', '1'],
|
||||
]
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
test('Testing moving last item in the row to the beginning', () => {
|
||||
const data = {
|
||||
contentOrder: [
|
||||
['1', '2', '3'],
|
||||
],
|
||||
srcBlockId: '3',
|
||||
srcBlockX: 0,
|
||||
srcBlockY: 2,
|
||||
dstBlockX: 0,
|
||||
dstBlockY: 0,
|
||||
dstBlockId: '1',
|
||||
moveTo: 'left' as Position,
|
||||
}
|
||||
|
||||
const result = dragAndDropRearrange(data)
|
||||
const expected = [
|
||||
['3', '1', '2'],
|
||||
]
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
test('Testing moving item from beginning of row to the middle of row', () => {
|
||||
const data = {
|
||||
contentOrder: [
|
||||
['1', '2', '3'],
|
||||
],
|
||||
srcBlockId: '1',
|
||||
srcBlockX: 0,
|
||||
srcBlockY: 0,
|
||||
dstBlockX: 0,
|
||||
dstBlockY: 2,
|
||||
dstBlockId: '3',
|
||||
moveTo: 'left' as Position,
|
||||
}
|
||||
|
||||
const result = dragAndDropRearrange(data)
|
||||
const expected = [
|
||||
['2', '1', '3'],
|
||||
]
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
test('Testing swapping two items in the same row by moving second item to the left of the first item', () => {
|
||||
const data = {
|
||||
contentOrder: [
|
||||
['1', '2'],
|
||||
],
|
||||
srcBlockId: '2',
|
||||
srcBlockX: 0,
|
||||
srcBlockY: 1,
|
||||
dstBlockX: 0,
|
||||
dstBlockY: 0,
|
||||
dstBlockId: '1',
|
||||
moveTo: 'left' as Position,
|
||||
}
|
||||
|
||||
const result = dragAndDropRearrange(data)
|
||||
const expected = [
|
||||
['2', '1'],
|
||||
]
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
test('Testing swapping two items in the same row by moving the first item to the right of the second item', () => {
|
||||
const data = {
|
||||
contentOrder: [
|
||||
['1', '2'],
|
||||
],
|
||||
srcBlockId: '1',
|
||||
srcBlockX: 0,
|
||||
srcBlockY: 0,
|
||||
dstBlockX: 0,
|
||||
dstBlockY: 1,
|
||||
dstBlockId: '2',
|
||||
moveTo: 'right' as Position,
|
||||
}
|
||||
|
||||
const result = dragAndDropRearrange(data)
|
||||
const expected = [
|
||||
['2', '1'],
|
||||
]
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
test('Testing moving a single item in the first row into the middle of second row using left operation', () => {
|
||||
const data = {
|
||||
contentOrder: [
|
||||
'4',
|
||||
['1', '3'],
|
||||
],
|
||||
srcBlockId: '4',
|
||||
srcBlockX: 0,
|
||||
srcBlockY: -1,
|
||||
dstBlockX: 1,
|
||||
dstBlockY: 1,
|
||||
dstBlockId: '3',
|
||||
moveTo: 'left' as Position,
|
||||
}
|
||||
|
||||
const result = dragAndDropRearrange(data)
|
||||
const expected = [
|
||||
['1', '4', '3'],
|
||||
]
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
test('Testing moving a single item in the first row into the middle of second row using right operation', () => {
|
||||
const data = {
|
||||
contentOrder: [
|
||||
'4',
|
||||
['1', '3'],
|
||||
],
|
||||
srcBlockId: '4',
|
||||
srcBlockX: 0,
|
||||
srcBlockY: -1,
|
||||
dstBlockX: 1,
|
||||
dstBlockY: 0,
|
||||
dstBlockId: '1',
|
||||
moveTo: 'right' as Position,
|
||||
}
|
||||
|
||||
const result = dragAndDropRearrange(data)
|
||||
const expected = [
|
||||
['1', '4', '3'],
|
||||
]
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
test('Testing moving a single item in the last row into the middle of first row', () => {
|
||||
const data = {
|
||||
contentOrder: [
|
||||
['1', '3'],
|
||||
'4',
|
||||
],
|
||||
srcBlockId: '4',
|
||||
srcBlockX: 1,
|
||||
srcBlockY: -1,
|
||||
dstBlockX: 0,
|
||||
dstBlockY: 0,
|
||||
dstBlockId: '1',
|
||||
moveTo: 'right' as Position,
|
||||
}
|
||||
|
||||
const result = dragAndDropRearrange(data)
|
||||
const expected = [
|
||||
['1', '4', '3'],
|
||||
]
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
test('Testing moving a single item in the last row above the first row', () => {
|
||||
const data = {
|
||||
contentOrder: [
|
||||
['1', '3'],
|
||||
'4',
|
||||
],
|
||||
srcBlockId: '4',
|
||||
srcBlockX: 1,
|
||||
srcBlockY: -1,
|
||||
dstBlockX: 0,
|
||||
dstBlockY: 0,
|
||||
dstBlockId: '1',
|
||||
moveTo: 'aboveRow' as Position,
|
||||
}
|
||||
|
||||
const result = dragAndDropRearrange(data)
|
||||
const expected = [
|
||||
'4',
|
||||
['1', '3'],
|
||||
]
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
test('Testing moving an item out of a row', () => {
|
||||
const data = {
|
||||
contentOrder: [
|
||||
['1', '3'],
|
||||
'4',
|
||||
],
|
||||
srcBlockId: '3',
|
||||
srcBlockX: 0,
|
||||
srcBlockY: 1,
|
||||
dstBlockX: 1,
|
||||
dstBlockY: -1,
|
||||
dstBlockId: '4',
|
||||
moveTo: 'belowRow' as Position,
|
||||
}
|
||||
|
||||
const result = dragAndDropRearrange(data)
|
||||
const expected = [
|
||||
'1',
|
||||
'4',
|
||||
'3',
|
||||
]
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
test('Testing moving an item out of a row and creating a new row with a single item at the end', () => {
|
||||
const data = {
|
||||
contentOrder: [
|
||||
['1', '3'],
|
||||
'4',
|
||||
],
|
||||
srcBlockId: '3',
|
||||
srcBlockX: 0,
|
||||
srcBlockY: 1,
|
||||
dstBlockX: 1,
|
||||
dstBlockY: -1,
|
||||
dstBlockId: '4',
|
||||
moveTo: 'right' as Position,
|
||||
}
|
||||
|
||||
const result = dragAndDropRearrange(data)
|
||||
const expected = [
|
||||
'1',
|
||||
['4', '3'],
|
||||
]
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
|
||||
test('Testing moving an item out of a row and creating a new row with a single item at the beginning', () => {
|
||||
const data = {
|
||||
contentOrder: [
|
||||
['1', '3'],
|
||||
'4',
|
||||
],
|
||||
srcBlockId: '3',
|
||||
srcBlockX: 0,
|
||||
srcBlockY: 1,
|
||||
dstBlockX: 1,
|
||||
dstBlockY: -1,
|
||||
dstBlockId: '4',
|
||||
moveTo: 'left' as Position,
|
||||
}
|
||||
|
||||
const result = dragAndDropRearrange(data)
|
||||
const expected = [
|
||||
'1',
|
||||
['3', '4'],
|
||||
]
|
||||
expect(result).toEqual(expected)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import {Position} from './cardDetailContents'
|
||||
|
||||
type DragAndDropRearrangeData = {
|
||||
contentOrder: Array<string|string[]>,
|
||||
srcBlockId: string,
|
||||
srcBlockX: number,
|
||||
srcBlockY: number,
|
||||
dstBlockX: number,
|
||||
dstBlockY: number,
|
||||
dstBlockId: string,
|
||||
moveTo: Position,
|
||||
}
|
||||
|
||||
export const dragAndDropRearrange =
|
||||
(data: DragAndDropRearrangeData): Array<string|string[]> => {
|
||||
const {contentOrder, srcBlockX, srcBlockY, dstBlockX, dstBlockY, moveTo, srcBlockId, dstBlockId} = data
|
||||
const newContentOrder: Array<string|string[]> = JSON.parse(JSON.stringify(contentOrder))
|
||||
|
||||
const copySrcBlockX = srcBlockX
|
||||
const copySrcBlockY = srcBlockY
|
||||
|
||||
let copyDstBlockX = dstBlockX
|
||||
let copyDstBlockY = dstBlockY
|
||||
|
||||
// Delete the block we are moving first then move it to the correct place
|
||||
|
||||
// Delete Src Block
|
||||
if (copySrcBlockY > -1) {
|
||||
(newContentOrder[copySrcBlockX] as string[]).splice(copySrcBlockY, 1)
|
||||
|
||||
if (newContentOrder[copySrcBlockX].length === 1 && copySrcBlockX !== copyDstBlockX) {
|
||||
newContentOrder.splice(copySrcBlockX, 1, newContentOrder[copySrcBlockX][0])
|
||||
}
|
||||
} else {
|
||||
newContentOrder.splice(copySrcBlockX, 1)
|
||||
|
||||
if (copyDstBlockX > copySrcBlockX) {
|
||||
copyDstBlockX -= 1
|
||||
}
|
||||
}
|
||||
|
||||
if (moveTo === 'right') {
|
||||
if (copyDstBlockY > -1) {
|
||||
if (copyDstBlockX === copySrcBlockX && copyDstBlockY > copySrcBlockY && copySrcBlockY > -1) {
|
||||
copyDstBlockY -= 1
|
||||
}
|
||||
|
||||
(newContentOrder[copyDstBlockX] as string[]).splice(copyDstBlockY + 1, 0, srcBlockId)
|
||||
} else {
|
||||
newContentOrder.splice(copyDstBlockX, 1, [dstBlockId, srcBlockId])
|
||||
}
|
||||
} else if (moveTo === 'left') {
|
||||
if (copyDstBlockY > -1) {
|
||||
if (copyDstBlockX === copySrcBlockX && copyDstBlockY > copySrcBlockY && copySrcBlockY > -1) {
|
||||
copyDstBlockY -= 1
|
||||
}
|
||||
|
||||
(newContentOrder[copyDstBlockX] as string[]).splice(copyDstBlockY, 0, srcBlockId)
|
||||
} else {
|
||||
newContentOrder.splice(copyDstBlockX, 1, [srcBlockId, dstBlockId])
|
||||
}
|
||||
} else if (moveTo === 'aboveRow') {
|
||||
newContentOrder.splice(copyDstBlockX, 0, srcBlockId)
|
||||
} else if (moveTo === 'belowRow') {
|
||||
newContentOrder.splice(copyDstBlockX + 1, 0, srcBlockId)
|
||||
}
|
||||
|
||||
return newContentOrder
|
||||
}
|
|
@ -60,7 +60,7 @@ describe('components/cardDetail/CardDetailProperties', () => {
|
|||
cardTemplate.fields.isTemplate = true
|
||||
|
||||
test('should match snapshot', async () => {
|
||||
const componet = wrapIntl((
|
||||
const component = wrapIntl((
|
||||
<CardDetailProperties
|
||||
board={board!}
|
||||
card={card}
|
||||
|
@ -73,7 +73,7 @@ describe('components/cardDetail/CardDetailProperties', () => {
|
|||
/>
|
||||
))
|
||||
|
||||
const {container} = render(componet)
|
||||
const {container} = render(component)
|
||||
expect(container).toMatchSnapshot()
|
||||
})
|
||||
|
||||
|
|
|
@ -43,7 +43,16 @@ const ContentBlock = React.memo((props: Props): JSX.Element => {
|
|||
|
||||
const index = cords.x
|
||||
const colIndex = (cords.y || cords.y === 0) && cords.y > -1 ? cords.y : -1
|
||||
const contentOrder = card.fields.contentOrder.slice()
|
||||
const contentOrder: Array<string|string[]> = []
|
||||
if (card.fields.contentOrder) {
|
||||
for (const contentId of card.fields.contentOrder) {
|
||||
if (typeof contentId === 'string') {
|
||||
contentOrder.push(contentId)
|
||||
} else {
|
||||
contentOrder.push(contentId.slice())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const className = 'ContentBlock octo-block'
|
||||
return (
|
||||
|
|
|
@ -7,6 +7,7 @@ import {Utils} from '../utils'
|
|||
import './markdownEditor.scss'
|
||||
|
||||
type Props = {
|
||||
id?: string
|
||||
text?: string
|
||||
placeholderText?: string
|
||||
className?: string
|
||||
|
@ -19,10 +20,10 @@ type Props = {
|
|||
}
|
||||
|
||||
const MarkdownEditor = (props: Props): JSX. Element => {
|
||||
const {placeholderText, onFocus, onBlur, onChange, text} = props
|
||||
const [uniqueId] = useState(Utils.createGuid())
|
||||
|
||||
const {placeholderText, onFocus, onBlur, onChange, text, id} = props
|
||||
const [isEditing, setIsEditing] = useState(false)
|
||||
const [uniqueId] = useState(id || Utils.createGuid())
|
||||
|
||||
const [active, setActive] = useState(false)
|
||||
const [editorInstance, setEditorInstance] = useState<any>()
|
||||
const editorOptions = useMemo(() => ({
|
||||
|
|
Loading…
Reference in a new issue