From 3c73d86f7a8a91b429ea8f1f5ab9c340a7438f6f Mon Sep 17 00:00:00 2001 From: Cory Forsyth Date: Wed, 16 Dec 2015 16:54:48 -0500 Subject: [PATCH] Refactor Position#move to work correctly when prev/next is list section fixes #270 --- src/js/utils/cursor/position.js | 40 ++- tests/acceptance/cursor-movement-test.js | 308 +++++++++++++++++------ tests/unit/utils/cursor-position-test.js | 120 +++++++++ 3 files changed, 377 insertions(+), 91 deletions(-) create mode 100644 tests/unit/utils/cursor-position-test.js diff --git a/src/js/utils/cursor/position.js b/src/js/utils/cursor/position.js index 65f556d53..5b1e43d01 100644 --- a/src/js/utils/cursor/position.js +++ b/src/js/utils/cursor/position.js @@ -76,6 +76,14 @@ const Position = class Position { return this.isEqual(this.section.tailPosition()); } + /** + * This method returns a new Position instance, it does not modify + * this instance. + * + * @param {Direction} direction to move + * @return {Position|null} Return the position one unit in the given + * direction, or null if it is not possible to move that direction + */ move(direction) { switch (direction) { case DIRECTION.BACKWARD: @@ -87,23 +95,27 @@ const Position = class Position { } } + /** + * @return {Position|null} + */ moveLeft() { - if (this.offset > 0) { - return new Position(this.section, this.offset - 1); - } else if (this.section.prev) { - return new Position(this.section.prev, this.section.prev.length); + if (this.isHead()) { + let prev = this.section.previousLeafSection(); + return prev && prev.tailPosition(); } else { - return null; + return new Position(this.section, this.offset - 1); } } + /** + * @return {Position|null} + */ moveRight() { - if (this.offset < this.section.length) { - return new Position(this.section, this.offset + 1); - } else if (this.section.next) { - return new Position(this.section.next, 0); + if (this.isTail()) { + let next = this.section.nextLeafSection(); + return next && next.headPosition(); } else { - return null; + return new Position(this.section, this.offset + 1); } } @@ -123,7 +135,8 @@ const Position = class Position { const marker = renderNode.postNode; section = marker.section; - if (!section) { throw new Error(`Could not find parent section for mapped text node "${textNode.textContent}"`); } + assert(`Could not find parent section for mapped text node "${textNode.textContent}"`, + !!section); offsetInSection = section.offsetOfMarker(marker, offsetInNode); } else { // all text nodes should be rendered by markers except: @@ -131,7 +144,8 @@ const Position = class Position { // * text nodes created by the browser during text input // both of these should have rendered parent sections, though section = findParentSectionFromNode(renderTree, textNode); - if (!section) { throw new Error(`Could not find parent section for un-mapped text node "${textNode.textContent}"`); } + assert(`Could not find parent section for un-mapped text node "${textNode.textContent}"`, + !!section); offsetInSection = findOffsetInSection(section, textNode, offsetInNode); } @@ -178,7 +192,7 @@ const Position = class Position { * @private */ get markerPosition() { - if (!this.section) { throw new Error('cannot get markerPosition without a section'); } + assert('Cannot get markerPosition without a section', !!this.section); return this.section.markerPositionAtOffset(this.offset); } diff --git a/tests/acceptance/cursor-movement-test.js b/tests/acceptance/cursor-movement-test.js index 5678b77ea..c2e491af4 100644 --- a/tests/acceptance/cursor-movement-test.js +++ b/tests/acceptance/cursor-movement-test.js @@ -32,36 +32,31 @@ test('left arrow when at the end of a card moves the cursor across the card', as }); editor = new Editor({mobiledoc, cards}); editor.render(editorElement); + let cardHead = editor.post.sections.head.headPosition(); // Before zwnj Helpers.dom.moveCursorTo(editorElement.firstChild.lastChild, 0); Helpers.dom.triggerLeftArrowKey(editor); let { offsets } = editor.cursor; - assert.ok(offsets.head.section === editor.post.sections.head, - 'Cursor is positioned on first section'); - assert.equal(offsets.head.offset, 0, - 'Cursor is positioned at offset 0'); + assert.positionIsEqual(offsets.head, cardHead); + assert.positionIsEqual(offsets.tail, cardHead); // After zwnj Helpers.dom.moveCursorTo(editorElement.firstChild.lastChild, 1); Helpers.dom.triggerLeftArrowKey(editor); offsets = editor.cursor.offsets; - assert.ok(offsets.head.section === editor.post.sections.head, - 'Cursor is positioned on first section'); - assert.equal(offsets.head.offset, 0, - 'Cursor is positioned at offset 0'); + assert.positionIsEqual(offsets.head, cardHead); + assert.positionIsEqual(offsets.tail, cardHead); // On wrapper Helpers.dom.moveCursorTo(editorElement.firstChild, 2); Helpers.dom.triggerLeftArrowKey(editor); offsets = editor.cursor.offsets; - assert.ok(offsets.head.section === editor.post.sections.head, - 'Cursor is positioned on first section'); - assert.equal(offsets.head.offset, 0, - 'Cursor is positioned at offset 0'); + assert.positionIsEqual(offsets.head, cardHead); + assert.positionIsEqual(offsets.tail, cardHead); }); test('left arrow when at the start of a card moves the cursor to the previous section', assert => { @@ -73,6 +68,7 @@ test('left arrow when at the start of a card moves the cursor to the previous se }); editor = new Editor({mobiledoc, cards}); editor.render(editorElement); + let sectionTail = editor.post.sections.head.tailPosition(); // Before zwnj let sectionElement = editor.post.sections.tail.renderNode.element; @@ -80,10 +76,8 @@ test('left arrow when at the start of a card moves the cursor to the previous se Helpers.dom.triggerLeftArrowKey(editor); let { offsets } = editor.cursor; - assert.ok(offsets.head.section === editor.post.sections.head, - 'Cursor is positioned on first section'); - assert.equal(offsets.head.offset, 0, - 'Cursor is positioned at offset 0'); + assert.positionIsEqual(offsets.head, sectionTail); + assert.positionIsEqual(offsets.tail, sectionTail); // After zwnj sectionElement = editor.post.sections.tail.renderNode.element; @@ -91,13 +85,42 @@ test('left arrow when at the start of a card moves the cursor to the previous se Helpers.dom.triggerLeftArrowKey(editor); offsets = editor.cursor.offsets; - assert.ok(offsets.head.section === editor.post.sections.head, - 'Cursor is positioned on first section'); - assert.equal(offsets.head.offset, 0, - 'Cursor is positioned at offset 0'); + assert.positionIsEqual(offsets.head, sectionTail); + assert.positionIsEqual(offsets.tail, sectionTail); }); -test('right arrow moves the cursor across the card', assert => { +test('left arrow when at the start of a card moves to previous list item', assert => { + let mobiledoc = Helpers.mobiledoc.build( + ({post, listSection, listItem, marker, cardSection}) => { + return post([ + listSection('ul', [listItem([marker('abc')])]), + cardSection('my-card') + ]); + }); + editor = new Editor({mobiledoc, cards}); + editor.render(editorElement); + let itemTail = editor.post.sections.head.items.head.tailPosition(); + + // Before zwnj + let sectionElement = editor.post.sections.tail.renderNode.element; + Helpers.dom.moveCursorTo(sectionElement.firstChild, 0); + Helpers.dom.triggerLeftArrowKey(editor); + let { offsets } = editor.cursor; + + assert.positionIsEqual(offsets.head, itemTail); + assert.positionIsEqual(offsets.tail, itemTail); + + // After zwnj + sectionElement = editor.post.sections.tail.renderNode.element; + Helpers.dom.moveCursorTo(sectionElement.firstChild, 1); + Helpers.dom.triggerLeftArrowKey(editor); + offsets = editor.cursor.offsets; + + assert.positionIsEqual(offsets.head, itemTail); + assert.positionIsEqual(offsets.tail, itemTail); +}); + +test('right arrow at start of card moves the cursor across the card', assert => { let mobiledoc = Helpers.mobiledoc.build(({post, cardSection}) => { return post([ cardSection('my-card') @@ -105,26 +128,23 @@ test('right arrow moves the cursor across the card', assert => { }); editor = new Editor({mobiledoc, cards}); editor.render(editorElement); + let cardTail = editor.post.sections.head.tailPosition(); // Before zwnj Helpers.dom.moveCursorTo(editorElement.firstChild.firstChild, 0); Helpers.dom.triggerRightArrowKey(editor); let { offsets } = editor.cursor; - assert.ok(offsets.head.section === editor.post.sections.head, - 'Cursor is positioned on first section'); - assert.equal(offsets.head.offset, 1, - 'Cursor is positioned at offset 1'); + assert.positionIsEqual(offsets.head, cardTail); + assert.positionIsEqual(offsets.tail, cardTail); // After zwnj Helpers.dom.moveCursorTo(editorElement.firstChild.firstChild, 1); Helpers.dom.triggerRightArrowKey(editor); offsets = editor.cursor.offsets; - assert.ok(offsets.head.section === editor.post.sections.head, - 'Cursor is positioned on first section'); - assert.equal(offsets.head.offset, 1, - 'Cursor is positioned at offset 1'); + assert.positionIsEqual(offsets.head, cardTail); + assert.positionIsEqual(offsets.tail, cardTail); }); test('right arrow at end of card moves cursor to next section', assert => { @@ -136,6 +156,7 @@ test('right arrow at end of card moves cursor to next section', assert => { }); editor = new Editor({mobiledoc, cards}); editor.render(editorElement); + let sectionHead = editor.post.sections.tail.headPosition(); // Before zwnj let sectionElement = editor.post.sections.head.renderNode.element; @@ -143,10 +164,8 @@ test('right arrow at end of card moves cursor to next section', assert => { Helpers.dom.triggerRightArrowKey(editor); let { offsets } = editor.cursor; - assert.ok(offsets.head.section === editor.post.sections.tail, - 'Cursor is positioned on tail section'); - assert.equal(offsets.head.offset, 0, - 'Cursor is positioned at offset 0'); + assert.positionIsEqual(offsets.head, sectionHead); + assert.positionIsEqual(offsets.tail, sectionHead); // After zwnj sectionElement = editor.post.sections.head.renderNode.element; @@ -154,10 +173,43 @@ test('right arrow at end of card moves cursor to next section', assert => { Helpers.dom.triggerRightArrowKey(editor); offsets = editor.cursor.offsets; - assert.ok(offsets.head.section === editor.post.sections.tail, - 'Cursor is positioned on tail section'); - assert.equal(offsets.head.offset, 0, - 'Cursor is positioned at offset 0'); + // On wrapper + Helpers.dom.moveCursorTo(editorElement.firstChild, 2); + Helpers.dom.triggerRightArrowKey(editor); + offsets = editor.cursor.offsets; + + assert.positionIsEqual(offsets.head, sectionHead); + assert.positionIsEqual(offsets.tail, sectionHead); +}); + +test('right arrow at end of card moves cursor to next list item', assert => { + let mobiledoc = Helpers.mobiledoc.build( + ({post, listSection, listItem, marker, cardSection}) => { + return post([ + cardSection('my-card'), + listSection('ul', [listItem([marker('abc')])]) + ]); + }); + editor = new Editor({mobiledoc, cards}); + editor.render(editorElement); + let itemHead = editor.post.sections.tail.items.head.headPosition(); + + // Before zwnj + let sectionElement = editor.post.sections.head.renderNode.element; + Helpers.dom.moveCursorTo(sectionElement.lastChild, 0); + Helpers.dom.triggerRightArrowKey(editor); + let { offsets } = editor.cursor; + + assert.positionIsEqual(offsets.head, itemHead); + assert.positionIsEqual(offsets.tail, itemHead); + + // After zwnj + Helpers.dom.moveCursorTo(sectionElement.lastChild, 1); + Helpers.dom.triggerRightArrowKey(editor); + offsets = editor.cursor.offsets; + + assert.positionIsEqual(offsets.head, itemHead); + assert.positionIsEqual(offsets.tail, itemHead); }); module('Acceptance: Cursor Movement w/ shift', { @@ -183,51 +235,98 @@ if (supportsSelectionExtend()) { editor = new Editor({mobiledoc, cards}); editor.render(editorElement); + let cardHead = editor.post.sections.head.headPosition(); + let cardTail = editor.post.sections.head.tailPosition(); + // Before zwnj Helpers.dom.moveCursorTo(editorElement.firstChild.lastChild, 0); Helpers.dom.triggerLeftArrowKey(editor, MODIFIERS.SHIFT); let { offsets } = editor.cursor; - assert.ok(offsets.head.section === editor.post.sections.head, - 'selection head is positioned on first section'); - assert.ok(offsets.tail.section === editor.post.sections.head, - 'selection tail is positioned on first section'); - assert.equal(offsets.head.offset, 0, - 'selection head is positioned at offset 0'); - assert.equal(offsets.tail.offset, 1, - 'selection tail is positioned at offset 1'); + assert.positionIsEqual(offsets.head, cardHead); + assert.positionIsEqual(offsets.tail, cardTail); // After zwnj Helpers.dom.moveCursorTo(editorElement.firstChild.lastChild, 1); Helpers.dom.triggerLeftArrowKey(editor, MODIFIERS.SHIFT); offsets = editor.cursor.offsets; - assert.ok(offsets.head.section === editor.post.sections.head, - 'selection head is positioned on first section'); - assert.ok(offsets.tail.section === editor.post.sections.head, - 'selection tail is positioned on first section'); - assert.equal(offsets.head.offset, 0, - 'selection head is positioned at offset 0'); - assert.equal(offsets.tail.offset, 1, - 'selection tail is positioned at offset 1'); + assert.positionIsEqual(offsets.head, cardHead); + assert.positionIsEqual(offsets.tail, cardTail); // On wrapper Helpers.dom.moveCursorTo(editorElement.firstChild, 2); Helpers.dom.triggerLeftArrowKey(editor, MODIFIERS.SHIFT); offsets = editor.cursor.offsets; - assert.ok(offsets.head.section === editor.post.sections.head, - 'selection head is positioned on first section'); - assert.ok(offsets.tail.section === editor.post.sections.head, - 'selection tail is positioned on first section'); - assert.equal(offsets.head.offset, 0, - 'selection head is positioned at offset 0'); - assert.equal(offsets.tail.offset, 1, - 'selection tail is positioned at offset 1'); + assert.positionIsEqual(offsets.head, cardHead); + assert.positionIsEqual(offsets.tail, cardTail); + }); + + test('left arrow at start of card moves selection to prev section', assert => { + let mobiledoc = Helpers.mobiledoc.build( + ({post, markupSection, marker, cardSection}) => { + return post([ + markupSection('p', [marker('abc')]), + cardSection('my-card') + ]); + }); + editor = new Editor({mobiledoc, cards}); + editor.render(editorElement); + + let cardHead = editor.post.sections.tail.headPosition(); + let sectionTail = editor.post.sections.head.tailPosition(); + + // Before zwnj + Helpers.dom.moveCursorTo(editorElement.lastChild.firstChild, 0); + Helpers.dom.triggerLeftArrowKey(editor, MODIFIERS.SHIFT); + let { offsets } = editor.cursor; + + assert.positionIsEqual(offsets.head, sectionTail); + assert.positionIsEqual(offsets.tail, cardHead); + + // After zwnj + Helpers.dom.moveCursorTo(editorElement.lastChild.firstChild, 1); + Helpers.dom.triggerLeftArrowKey(editor, MODIFIERS.SHIFT); + offsets = editor.cursor.offsets; + + assert.positionIsEqual(offsets.head, sectionTail); + assert.positionIsEqual(offsets.tail, cardHead); + }); + + test('left arrow at start of card moves selection to prev list item', assert => { + let mobiledoc = Helpers.mobiledoc.build( + ({post, listSection, listItem, marker, cardSection}) => { + return post([ + listSection('ul', [listItem([marker('abc')])]), + cardSection('my-card') + ]); + }); + editor = new Editor({mobiledoc, cards}); + editor.render(editorElement); + + let cardHead = editor.post.sections.tail.headPosition(); + let sectionTail = editor.post.sections.head.items.head.tailPosition(); + + // Before zwnj + Helpers.dom.moveCursorTo(editorElement.lastChild.firstChild, 0); + Helpers.dom.triggerLeftArrowKey(editor, MODIFIERS.SHIFT); + let { offsets } = editor.cursor; + + assert.positionIsEqual(offsets.head, sectionTail); + assert.positionIsEqual(offsets.tail, cardHead); + + // After zwnj + Helpers.dom.moveCursorTo(editorElement.lastChild.firstChild, 1); + Helpers.dom.triggerLeftArrowKey(editor, MODIFIERS.SHIFT); + offsets = editor.cursor.offsets; + + assert.positionIsEqual(offsets.head, sectionTail); + assert.positionIsEqual(offsets.tail, cardHead); }); } -test('right arrow moves the cursor across the card', assert => { +test('right arrow at start of card moves the cursor across the card', assert => { let mobiledoc = Helpers.mobiledoc.build(({post, cardSection}) => { return post([ cardSection('my-card') @@ -236,31 +335,84 @@ test('right arrow moves the cursor across the card', assert => { editor = new Editor({mobiledoc, cards}); editor.render(editorElement); + let cardHead = editor.post.sections.head.headPosition(); + let cardTail = editor.post.sections.head.tailPosition(); + // Before zwnj Helpers.dom.moveCursorTo(editorElement.firstChild.firstChild, 0); Helpers.dom.triggerRightArrowKey(editor, MODIFIERS.SHIFT); let { offsets } = editor.cursor; - assert.ok(offsets.head.section === editor.post.sections.head, - 'selection head is positioned on first section'); - assert.ok(offsets.tail.section === editor.post.sections.head, - 'selection tail is positioned on first section'); - assert.equal(offsets.head.offset, 0, - 'selection head is positioned at offset 0'); - assert.equal(offsets.tail.offset, 1, - 'selection tail is positioned at offset 1'); + assert.positionIsEqual(offsets.head, cardHead); + assert.positionIsEqual(offsets.tail, cardTail); // After zwnj Helpers.dom.moveCursorTo(editorElement.firstChild.firstChild, 1); Helpers.dom.triggerRightArrowKey(editor, MODIFIERS.SHIFT); offsets = editor.cursor.offsets; - assert.ok(offsets.head.section === editor.post.sections.head, - 'selection head is positioned on first section'); - assert.ok(offsets.tail.section === editor.post.sections.head, - 'selection tail is positioned on first section'); - assert.equal(offsets.head.offset, 0, - 'selection head is positioned at offset 0'); - assert.equal(offsets.tail.offset, 1, - 'selection tail is positioned at offset 1'); + assert.positionIsEqual(offsets.head, cardHead); + assert.positionIsEqual(offsets.tail, cardTail); +}); + +test('right arrow at end of card moves to next section', (assert) => { + let mobiledoc = Helpers.mobiledoc.build( + ({post, markupSection, marker, cardSection}) => { + return post([ + cardSection('my-card'), + markupSection('p', [marker('abc')]) + ]); + }); + editor = new Editor({mobiledoc, cards}); + editor.render(editorElement); + + let cardTail = editor.post.sections.head.tailPosition(); + let sectionHead = editor.post.sections.tail.headPosition(); + + // Before zwnj + Helpers.dom.moveCursorTo(editorElement.firstChild.lastChild, 0); + Helpers.dom.triggerRightArrowKey(editor, MODIFIERS.SHIFT); + let { offsets } = editor.cursor; + + assert.positionIsEqual(offsets.head, cardTail); + assert.positionIsEqual(offsets.tail, sectionHead); + + // After zwnj + Helpers.dom.moveCursorTo(editorElement.firstChild.lastChild, 1); + Helpers.dom.triggerRightArrowKey(editor, MODIFIERS.SHIFT); + offsets = editor.cursor.offsets; + + assert.positionIsEqual(offsets.head, cardTail); + assert.positionIsEqual(offsets.tail, sectionHead); +}); + +test('right arrow at end of card moves to next list item', (assert) => { + let mobiledoc = Helpers.mobiledoc.build( + ({post, listSection, listItem, marker, cardSection}) => { + return post([ + cardSection('my-card'), + listSection('ul', [listItem([marker('abc')])]) + ]); + }); + editor = new Editor({mobiledoc, cards}); + editor.render(editorElement); + + let cardTail = editor.post.sections.head.tailPosition(); + let itemHead = editor.post.sections.tail.items.head.headPosition(); + + // Before zwnj + Helpers.dom.moveCursorTo(editorElement.firstChild.lastChild, 0); + Helpers.dom.triggerRightArrowKey(editor, MODIFIERS.SHIFT); + let { offsets } = editor.cursor; + + assert.positionIsEqual(offsets.head, cardTail); + assert.positionIsEqual(offsets.tail, itemHead); + + // After zwnj + Helpers.dom.moveCursorTo(editorElement.firstChild.lastChild, 1); + Helpers.dom.triggerRightArrowKey(editor, MODIFIERS.SHIFT); + offsets = editor.cursor.offsets; + + assert.positionIsEqual(offsets.head, cardTail); + assert.positionIsEqual(offsets.tail, itemHead); }); diff --git a/tests/unit/utils/cursor-position-test.js b/tests/unit/utils/cursor-position-test.js new file mode 100644 index 000000000..2660a4c59 --- /dev/null +++ b/tests/unit/utils/cursor-position-test.js @@ -0,0 +1,120 @@ +import Helpers from '../../test-helpers'; +import Position from 'mobiledoc-kit/utils/cursor/position'; + +const {module, test} = Helpers; + +module('Unit: Utils: Position'); + +test('#move moves forward and backward in markup section', (assert) => { + let post = Helpers.postAbstract.build(({post, markupSection, marker}) => { + return post([markupSection('p', [marker('abcd')])]); + }); + let position = new Position(post.sections.head, 'ab'.length); + let rightPosition = new Position(post.sections.head, 'abc'.length); + let leftPosition = new Position(post.sections.head, 'a'.length); + + assert.positionIsEqual(position.moveRight(), rightPosition, 'right position'); + assert.positionIsEqual(position.moveLeft(), leftPosition, 'left position'); +}); + +test('#move moves forward and backward between markup sections', (assert) => { + let post = Helpers.postAbstract.build(({post, markupSection, marker}) => { + return post([ + markupSection('p', [marker('a')]), + markupSection('p', [marker('b')]), + markupSection('p', [marker('c')]) + ]); + }); + let midHead = post.sections.objectAt(1).headPosition(); + let midTail = post.sections.objectAt(1).tailPosition(); + + let aTail = post.sections.head.tailPosition(); + let cHead = post.sections.tail.headPosition(); + + assert.positionIsEqual(midHead.moveLeft(), aTail, 'left to prev section'); + assert.positionIsEqual(midTail.moveRight(), cHead, 'right to next section'); +}); + +test('#move from one nested section to another', (assert) => { + let post = Helpers.postAbstract.build( + ({post, listSection, listItem, marker}) => { + return post([listSection('ul', [ + listItem([marker('a')]), + listItem([marker('b')]), + listItem([marker('c')]) + ])]); + }); + let midHead = post.sections.head.items.objectAt(1).headPosition(); + let midTail = post.sections.head.items.objectAt(1).tailPosition(); + + let aTail = post.sections.head.items.head.tailPosition(); + let cHead = post.sections.tail.items.tail.headPosition(); + + assert.positionIsEqual(midHead.moveLeft(), aTail, 'left to prev section'); + assert.positionIsEqual(midTail.moveRight(), cHead, 'right to next section'); +}); + +test('#move from last nested section to next un-nested section', (assert) => { + let post = Helpers.postAbstract.build( + ({post, listSection, listItem, markupSection, marker}) => { + return post([ + markupSection('p', [marker('a')]), + listSection('ul', [listItem([marker('b')])]), + markupSection('p', [marker('c')]) + ]); + }); + let midHead = post.sections.objectAt(1).items.head.headPosition(); + let midTail = post.sections.objectAt(1).items.head.tailPosition(); + + let aTail = post.sections.head.tailPosition(); + let cHead = post.sections.tail.headPosition(); + + assert.positionIsEqual(midHead.moveLeft(), aTail, 'left to prev section'); + assert.positionIsEqual(midTail.moveRight(), cHead, 'right to next section'); +}); + +test('#move across and beyond card section', (assert) => { + let post = Helpers.postAbstract.build( + ({post, cardSection, markupSection, marker}) => { + return post([ + markupSection('p', [marker('a')]), + cardSection('my-card'), + markupSection('p', [marker('c')]) + ]); + }); + let midHead = post.sections.objectAt(1).headPosition(); + let midTail = post.sections.objectAt(1).tailPosition(); + + let aTail = post.sections.head.tailPosition(); + let cHead = post.sections.tail.headPosition(); + + assert.positionIsEqual(midHead.moveLeft(), aTail, 'left to prev section'); + assert.positionIsEqual(midTail.moveRight(), cHead, 'right to next section'); + assert.positionIsEqual(midHead.moveRight(), midTail, 'move l-to-r across card'); + assert.positionIsEqual(midTail.moveLeft(), midHead, 'move r-to-l across card'); +}); + +test('#move across and beyond card section into list section', (assert) => { + let post = Helpers.postAbstract.build( + ({post, cardSection, listSection, listItem, marker}) => { + return post([ + listSection('ul', [ + listItem([marker('a1')]), + listItem([marker('a2')]) + ]), + cardSection('my-card'), + listSection('ul', [ + listItem([marker('c1')]), + listItem([marker('c2')]) + ]) + ]); + }); + let midHead = post.sections.objectAt(1).headPosition(); + let midTail = post.sections.objectAt(1).tailPosition(); + + let aTail = post.sections.head.items.tail.tailPosition(); + let cHead = post.sections.tail.items.head.headPosition(); + + assert.positionIsEqual(midHead.moveLeft(), aTail, 'left to prev section'); + assert.positionIsEqual(midTail.moveRight(), cHead, 'right to next section'); +});