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:
Hossein 2021-08-09 08:24:36 -04:00 committed by GitHub
parent 904dfc2158
commit cdc72c31f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 1595 additions and 54 deletions

View file

@ -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>
`;

View 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()
})
})

View file

@ -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) => {

View file

@ -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)
})
})

View file

@ -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
}

View file

@ -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()
})

View file

@ -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 (

View file

@ -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(() => ({