8
0

treewalker.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. /**
  2. * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. import Model from '../../src/model/model';
  6. import DocumentFragment from '../../src/model/documentfragment';
  7. import Element from '../../src/model/element';
  8. import Text from '../../src/model/text';
  9. import TreeWalker from '../../src/model/treewalker';
  10. import Position from '../../src/model/position';
  11. import Range from '../../src/model/range';
  12. import { expectToThrowCKEditorError } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
  13. describe( 'TreeWalker', () => {
  14. let model, doc, root, img1, paragraph, ba, r, img2, x,
  15. rootBeginning, rootEnding;
  16. beforeEach( () => {
  17. model = new Model();
  18. doc = model.document;
  19. root = doc.createRoot();
  20. // root
  21. // |- img1
  22. // |- p
  23. // |- B -bold
  24. // |- A -bold
  25. // |- R
  26. // |
  27. // |- img2
  28. // |
  29. // |- X
  30. ba = new Text( 'ba', { bold: true } );
  31. r = new Text( 'r' );
  32. img2 = new Element( 'img2' );
  33. x = new Text( 'x' );
  34. paragraph = new Element( 'p', [], [ ba, r, img2, x ] );
  35. img1 = new Element( 'img1' );
  36. root._insertChild( 0, [ img1, paragraph ] );
  37. rootBeginning = new Position( root, [ 0 ] );
  38. rootEnding = new Position( root, [ 2 ] );
  39. } );
  40. describe( 'constructor()', () => {
  41. it( 'should throw if neither boundaries nor starting position is set', () => {
  42. expectToThrowCKEditorError( () => {
  43. new TreeWalker(); // eslint-disable-line no-new
  44. }, /^model-tree-walker-no-start-position/, null );
  45. expectToThrowCKEditorError( () => {
  46. new TreeWalker( {} ); // eslint-disable-line no-new
  47. }, /^model-tree-walker-no-start-position/, null );
  48. expectToThrowCKEditorError( () => {
  49. new TreeWalker( { singleCharacters: true } ); // eslint-disable-line no-new
  50. }, /^model-tree-walker-no-start-position/, null );
  51. } );
  52. it( 'should throw if walking direction is unknown', () => {
  53. expectToThrowCKEditorError( () => {
  54. new TreeWalker( { startPosition: rootBeginning, direction: 'unknown' } ); // eslint-disable-line no-new
  55. }, /^model-tree-walker-unknown-direction/, model );
  56. } );
  57. } );
  58. describe( 'is()', () => {
  59. let treeWalker;
  60. beforeEach( () => {
  61. treeWalker = new TreeWalker( { startPosition: rootBeginning } );
  62. } );
  63. it( 'should return true for "treeWalker"', () => {
  64. expect( treeWalker.is( 'treeWalker' ) ).to.be.true;
  65. expect( treeWalker.is( 'model:treeWalker' ) ).to.be.true;
  66. } );
  67. it( 'should return false for incorrect values', () => {
  68. expect( treeWalker.is( 'model' ) ).to.be.false;
  69. expect( treeWalker.is( 'model:node' ) ).to.be.false;
  70. expect( treeWalker.is( 'text' ) ).to.be.false;
  71. expect( treeWalker.is( 'element', 'paragraph' ) ).to.be.false;
  72. expect( treeWalker.is() ).to.be.false;
  73. } );
  74. } );
  75. describe( 'iterate from start position `startPosition`', () => {
  76. let expected;
  77. beforeEach( () => {
  78. expected = [
  79. { type: 'elementStart', item: img1 },
  80. { type: 'elementEnd', item: img1 },
  81. { type: 'elementStart', item: paragraph },
  82. { type: 'text', data: 'ba', attrs: [ [ 'bold', true ] ] },
  83. { type: 'text', data: 'r', attrs: [] },
  84. { type: 'elementStart', item: img2 },
  85. { type: 'elementEnd', item: img2 },
  86. { type: 'text', data: 'x', attrs: [] },
  87. { type: 'elementEnd', item: paragraph }
  88. ];
  89. } );
  90. it( 'should provide iterator interface with default forward direction', () => {
  91. const iterator = new TreeWalker( { startPosition: rootBeginning } );
  92. let i = 0;
  93. for ( const value of iterator ) {
  94. expectValue( value, expected[ i ] );
  95. i++;
  96. }
  97. expect( i ).to.equal( expected.length );
  98. } );
  99. it( 'should provide iterator interface with forward direction', () => {
  100. const iterator = new TreeWalker( { startPosition: rootBeginning, direction: 'forward' } );
  101. let i = 0;
  102. for ( const value of iterator ) {
  103. expectValue( value, expected[ i ] );
  104. i++;
  105. }
  106. expect( i ).to.equal( expected.length );
  107. } );
  108. it( 'should provide iterator interface which backward direction', () => {
  109. const iterator = new TreeWalker( { startPosition: rootEnding, direction: 'backward' } );
  110. let i = expected.length;
  111. for ( const value of iterator ) {
  112. expectValue( value, expected[ --i ], { direction: 'backward' } );
  113. }
  114. expect( i ).to.equal( 0 );
  115. } );
  116. it( 'should start iterating at the startPosition witch is not a root bound', () => {
  117. const iterator = new TreeWalker( { startPosition: new Position( root, [ 1 ] ) } );
  118. let i = 2;
  119. for ( const value of iterator ) {
  120. expectValue( value, expected[ i ] );
  121. i++;
  122. }
  123. expect( i ).to.equal( expected.length );
  124. } );
  125. it( 'should start iterating at the startPosition witch is not a root bound, going backward', () => {
  126. const expected = [
  127. { type: 'elementStart', item: img1 },
  128. { type: 'elementEnd', item: img1 }
  129. ];
  130. const iterator = new TreeWalker( { startPosition: new Position( root, [ 1 ] ), direction: 'backward' } );
  131. let i = expected.length;
  132. for ( const value of iterator ) {
  133. expectValue( value, expected[ --i ], { direction: 'backward' } );
  134. }
  135. expect( i ).to.equal( 0 );
  136. } );
  137. } );
  138. describe( 'iterate trough the range `boundary`', () => {
  139. describe( 'range starts between elements', () => {
  140. let expected, range;
  141. beforeEach( () => {
  142. expected = [
  143. { type: 'elementStart', item: paragraph },
  144. { type: 'text', data: 'ba', attrs: [ [ 'bold', true ] ] },
  145. { type: 'text', data: 'r', attrs: [] },
  146. { type: 'elementStart', item: img2 },
  147. { type: 'elementEnd', item: img2 }
  148. ];
  149. range = new Range( new Position( root, [ 1 ] ), new Position( root, [ 1, 4 ] ) );
  150. } );
  151. it( 'should iterate over the range', () => {
  152. const iterator = new TreeWalker( { boundaries: range } );
  153. let i = 0;
  154. for ( const value of iterator ) {
  155. expectValue( value, expected[ i ] );
  156. i++;
  157. }
  158. expect( i ).to.equal( expected.length );
  159. } );
  160. it( 'should iterate over the range going backward', () => {
  161. const iterator = new TreeWalker( { boundaries: range, direction: 'backward' } );
  162. let i = expected.length;
  163. for ( const value of iterator ) {
  164. expectValue( value, expected[ --i ], { direction: 'backward' } );
  165. }
  166. expect( i ).to.equal( 0 );
  167. } );
  168. } );
  169. describe( 'range starts inside the text', () => {
  170. let expected, range;
  171. beforeEach( () => {
  172. expected = [
  173. { type: 'text', data: 'a', attrs: [ [ 'bold', true ] ] },
  174. { type: 'text', data: 'r', attrs: [] },
  175. { type: 'elementStart', item: img2 },
  176. { type: 'elementEnd', item: img2 }
  177. ];
  178. range = new Range( new Position( root, [ 1, 1 ] ), new Position( root, [ 1, 4 ] ) );
  179. } );
  180. it( 'should return part of the text', () => {
  181. const iterator = new TreeWalker( { boundaries: range } );
  182. let i = 0;
  183. for ( const value of iterator ) {
  184. expectValue( value, expected[ i ] );
  185. i++;
  186. }
  187. expect( i ).to.equal( expected.length );
  188. } );
  189. it( 'should return part of the text going backward', () => {
  190. const iterator = new TreeWalker( {
  191. boundaries: range,
  192. direction: 'backward' }
  193. );
  194. let i = expected.length;
  195. for ( const value of iterator ) {
  196. expectValue( value, expected[ --i ], { direction: 'backward' } );
  197. }
  198. expect( i ).to.equal( 0 );
  199. } );
  200. } );
  201. describe( 'range ends inside the text', () => {
  202. let expected, range;
  203. beforeEach( () => {
  204. expected = [
  205. { type: 'elementStart', item: img1 },
  206. { type: 'elementEnd', item: img1 },
  207. { type: 'elementStart', item: paragraph },
  208. { type: 'text', data: 'b', attrs: [ [ 'bold', true ] ] }
  209. ];
  210. range = new Range( rootBeginning, new Position( root, [ 1, 1 ] ) );
  211. } );
  212. it( 'should return part of the text', () => {
  213. const iterator = new TreeWalker( { boundaries: range } );
  214. let i = 0;
  215. for ( const value of iterator ) {
  216. expectValue( value, expected[ i ] );
  217. i++;
  218. }
  219. expect( i ).to.equal( expected.length );
  220. } );
  221. it( 'should return part of the text going backward', () => {
  222. const iterator = new TreeWalker( {
  223. boundaries: range,
  224. startPosition: range.end,
  225. direction: 'backward'
  226. } );
  227. let i = expected.length;
  228. for ( const value of iterator ) {
  229. expectValue( value, expected[ --i ], { direction: 'backward' } );
  230. }
  231. expect( i ).to.equal( 0 );
  232. } );
  233. } );
  234. describe( 'custom start position', () => {
  235. it( 'should iterating from the start position', () => {
  236. const expected = [
  237. { type: 'text', data: 'r', attrs: [] },
  238. { type: 'elementStart', item: img2 },
  239. { type: 'elementEnd', item: img2 }
  240. ];
  241. const range = new Range( new Position( root, [ 1 ] ), new Position( root, [ 1, 4 ] ) );
  242. const iterator = new TreeWalker( {
  243. boundaries: range,
  244. startPosition: new Position( root, [ 1, 2 ] )
  245. } );
  246. let i = 0;
  247. for ( const value of iterator ) {
  248. expectValue( value, expected[ i ] );
  249. i++;
  250. }
  251. expect( i ).to.equal( expected.length );
  252. } );
  253. it( 'should iterating from the start position going backward', () => {
  254. const expected = [
  255. { type: 'text', data: 'r', attrs: [] },
  256. { type: 'elementStart', item: img2 },
  257. { type: 'elementEnd', item: img2 }
  258. ];
  259. const range = new Range( new Position( root, [ 1, 2 ] ), new Position( root, [ 1, 6 ] ) );
  260. const iterator = new TreeWalker( {
  261. boundaries: range,
  262. startPosition: new Position( root, [ 1, 4 ] ),
  263. direction: 'backward'
  264. } );
  265. let i = expected.length;
  266. for ( const value of iterator ) {
  267. expectValue( value, expected[ --i ], { direction: 'backward' } );
  268. }
  269. expect( i ).to.equal( 0 );
  270. } );
  271. } );
  272. } );
  273. describe( 'iterate by every single characters `singleCharacter`', () => {
  274. describe( 'whole root', () => {
  275. let expected;
  276. beforeEach( () => {
  277. expected = [
  278. { type: 'elementStart', item: img1 },
  279. { type: 'elementEnd', item: img1 },
  280. { type: 'elementStart', item: paragraph },
  281. { type: 'text', data: 'b', attrs: [ [ 'bold', true ] ] },
  282. { type: 'text', data: 'a', attrs: [ [ 'bold', true ] ] },
  283. { type: 'text', data: 'r', attrs: [] },
  284. { type: 'elementStart', item: img2 },
  285. { type: 'elementEnd', item: img2 },
  286. { type: 'text', data: 'x', attrs: [] },
  287. { type: 'elementEnd', item: paragraph }
  288. ];
  289. } );
  290. it( 'should return single characters', () => {
  291. const iterator = new TreeWalker( { startPosition: rootBeginning, singleCharacters: true } );
  292. let i = 0;
  293. for ( const value of iterator ) {
  294. expectValue( value, expected[ i ] );
  295. i++;
  296. }
  297. expect( i ).to.equal( expected.length );
  298. } );
  299. it( 'should return single characters going backward', () => {
  300. const iterator = new TreeWalker( {
  301. startPosition: rootEnding,
  302. singleCharacters: true,
  303. direction: 'backward' }
  304. );
  305. let i = expected.length;
  306. for ( const value of iterator ) {
  307. expectValue( value, expected[ --i ], { direction: 'backward' } );
  308. }
  309. expect( i ).to.equal( 0 );
  310. } );
  311. } );
  312. describe( 'range', () => {
  313. let start, end, range, expected;
  314. beforeEach( () => {
  315. expected = [
  316. { type: 'text', data: 'b', attrs: [ [ 'bold', true ] ] },
  317. { type: 'text', data: 'a', attrs: [ [ 'bold', true ] ] },
  318. { type: 'text', data: 'r', attrs: [] },
  319. { type: 'elementStart', item: img2 }
  320. ];
  321. start = new Position( root, [ 1, 0 ] ); // p, 0
  322. end = new Position( root, [ 1, 3, 0 ] ); // img2, 0
  323. range = new Range( start, end );
  324. } );
  325. it( 'should respect boundaries', () => {
  326. const iterator = new TreeWalker( { boundaries: range, singleCharacters: true } );
  327. let i = 0;
  328. for ( const value of iterator ) {
  329. expectValue( value, expected[ i ] );
  330. i++;
  331. }
  332. expect( i ).to.equal( expected.length );
  333. } );
  334. it( 'should respect boundaries going backward', () => {
  335. const iterator = new TreeWalker( {
  336. boundaries: range,
  337. singleCharacters: true,
  338. startPosition: range.end,
  339. direction: 'backward'
  340. } );
  341. let i = expected.length;
  342. for ( const value of iterator ) {
  343. expectValue( value, expected[ --i ], { direction: 'backward' } );
  344. }
  345. expect( i ).to.equal( 0 );
  346. } );
  347. } );
  348. } );
  349. describe( 'iterate omitting child nodes and elementEnd `shallow`', () => {
  350. let expected;
  351. beforeEach( () => {
  352. expected = [
  353. { type: 'elementStart', item: img1 },
  354. { type: 'elementStart', item: paragraph }
  355. ];
  356. } );
  357. it( 'should not enter elements', () => {
  358. const iterator = new TreeWalker( { startPosition: rootBeginning, shallow: true } );
  359. let i = 0;
  360. for ( const value of iterator ) {
  361. expectValue( value, expected[ i ], { shallow: true } );
  362. i++;
  363. }
  364. expect( i ).to.equal( expected.length );
  365. } );
  366. it( 'should not enter elements going backward', () => {
  367. const iterator = new TreeWalker( { startPosition: rootEnding, shallow: true, direction: 'backward' } );
  368. let i = expected.length;
  369. for ( const value of iterator ) {
  370. expectValue( value, expected[ --i ], { shallow: true, direction: 'backward' } );
  371. }
  372. expect( i ).to.equal( 0 );
  373. } );
  374. } );
  375. describe( 'iterate omitting elementEnd `ignoreElementEnd`', () => {
  376. describe( 'merged text', () => {
  377. let expected;
  378. beforeEach( () => {
  379. expected = [
  380. { type: 'elementStart', item: img1 },
  381. { type: 'elementStart', item: paragraph },
  382. { type: 'text', data: 'ba', attrs: [ [ 'bold', true ] ] },
  383. { type: 'text', data: 'r', attrs: [] },
  384. { type: 'elementStart', item: img2 },
  385. { type: 'text', data: 'x', attrs: [] }
  386. ];
  387. } );
  388. it( 'should iterate ignoring elementEnd', () => {
  389. const iterator = new TreeWalker( { startPosition: rootBeginning, ignoreElementEnd: true } );
  390. let i = 0;
  391. for ( const value of iterator ) {
  392. expectValue( value, expected[ i ] );
  393. i++;
  394. }
  395. expect( i ).to.equal( expected.length );
  396. } );
  397. it( 'should iterate ignoring elementEnd going backward', () => {
  398. const iterator = new TreeWalker( {
  399. startPosition: rootEnding,
  400. ignoreElementEnd: true,
  401. direction: 'backward'
  402. } );
  403. let i = expected.length;
  404. for ( const value of iterator ) {
  405. expectValue( value, expected[ --i ], { direction: 'backward' } );
  406. }
  407. expect( i ).to.equal( 0 );
  408. } );
  409. } );
  410. describe( 'single character', () => {
  411. let expected;
  412. beforeEach( () => {
  413. expected = [
  414. { type: 'elementStart', item: img1 },
  415. { type: 'elementStart', item: paragraph },
  416. { type: 'text', data: 'b', attrs: [ [ 'bold', true ] ] },
  417. { type: 'text', data: 'a', attrs: [ [ 'bold', true ] ] },
  418. { type: 'text', data: 'r', attrs: [] },
  419. { type: 'elementStart', item: img2 },
  420. { type: 'text', data: 'x', attrs: [] }
  421. ];
  422. } );
  423. it( 'should return single characters ignoring elementEnd', () => {
  424. const iterator = new TreeWalker( {
  425. startPosition: rootBeginning,
  426. singleCharacters: true,
  427. ignoreElementEnd: true
  428. } );
  429. let i = 0;
  430. for ( const value of iterator ) {
  431. expectValue( value, expected[ i ] );
  432. i++;
  433. }
  434. expect( i ).to.equal( expected.length );
  435. } );
  436. it( 'should return single characters ignoring elementEnd going backward', () => {
  437. const iterator = new TreeWalker( {
  438. startPosition: rootEnding,
  439. singleCharacters: true,
  440. ignoreElementEnd: true,
  441. direction: 'backward'
  442. } );
  443. let i = expected.length;
  444. for ( const value of iterator ) {
  445. expectValue( value, expected[ --i ], { direction: 'backward' } );
  446. }
  447. expect( i ).to.equal( 0 );
  448. } );
  449. } );
  450. } );
  451. it( 'should iterate over document fragment', () => {
  452. const foo = new Text( 'foo' );
  453. const bar = new Text( 'bar' );
  454. const p = new Element( 'p', null, [ foo, bar ] );
  455. const docFrag = new DocumentFragment( [ p ] );
  456. const iterator = new TreeWalker( {
  457. startPosition: new Position( docFrag, [ 0 ] ),
  458. ignoreElementEnd: true
  459. } );
  460. const expected = [
  461. { type: 'elementStart', item: p },
  462. { type: 'text', data: 'foo', attrs: [] },
  463. { type: 'text', data: 'bar', attrs: [] }
  464. ];
  465. let i = 0;
  466. for ( const value of iterator ) {
  467. expectValue( value, expected[ i++ ], { ignoreElementEnd: true } );
  468. }
  469. } );
  470. describe( 'skip', () => {
  471. describe( 'forward treewalker', () => {
  472. it( 'should jump over all text nodes', () => {
  473. const walker = new TreeWalker( {
  474. startPosition: Position._createAt( paragraph, 0 )
  475. } );
  476. walker.skip( value => value.type == 'text' );
  477. expect( walker.position.parent ).to.equal( paragraph );
  478. expect( walker.position.offset ).to.equal( 3 );
  479. } );
  480. it( 'should do not move if the condition is false', () => {
  481. const walker = new TreeWalker( {
  482. startPosition: Position._createAt( paragraph, 1 )
  483. } );
  484. walker.skip( () => false );
  485. expect( walker.position.parent ).to.equal( paragraph );
  486. expect( walker.position.offset ).to.equal( 1 );
  487. } );
  488. it( 'should move to the end if the condition is true', () => {
  489. const walker = new TreeWalker( {
  490. startPosition: Position._createAt( paragraph, 1 )
  491. } );
  492. walker.skip( () => true );
  493. expect( walker.position.parent ).to.equal( rootEnding.parent );
  494. expect( walker.position.offset ).to.equal( rootEnding.offset );
  495. } );
  496. } );
  497. describe( 'backward treewalker', () => {
  498. it( 'should jump over all text nodes', () => {
  499. const walker = new TreeWalker( {
  500. startPosition: Position._createAt( paragraph, 3 ),
  501. direction: 'backward'
  502. } );
  503. walker.skip( value => value.type == 'text' );
  504. expect( walker.position.parent ).to.equal( paragraph );
  505. expect( walker.position.offset ).to.equal( 0 );
  506. } );
  507. it( 'should do not move if the condition is false', () => {
  508. const walker = new TreeWalker( {
  509. startPosition: Position._createAt( paragraph, 1 ),
  510. direction: 'backward'
  511. } );
  512. walker.skip( () => false );
  513. expect( walker.position.parent ).to.equal( paragraph );
  514. expect( walker.position.offset ).to.equal( 1 );
  515. } );
  516. it( 'should move to the end if the condition is true', () => {
  517. const walker = new TreeWalker( {
  518. startPosition: Position._createAt( paragraph, 1 ),
  519. direction: 'backward'
  520. } );
  521. walker.skip( () => true );
  522. expect( walker.position.parent ).to.equal( rootBeginning.parent );
  523. expect( walker.position.offset ).to.equal( rootBeginning.offset );
  524. } );
  525. } );
  526. } );
  527. } );
  528. function expectValue( value, expected, options ) {
  529. expect( value.type ).to.equal( expected.type );
  530. if ( value.type == 'text' ) {
  531. expectText( value, expected, options );
  532. } else if ( value.type == 'elementStart' ) {
  533. expectStart( value, expected, options );
  534. } else if ( value.type == 'elementEnd' ) {
  535. expectEnd( value, expected, options );
  536. }
  537. }
  538. function expectText( value, expected, options = {} ) {
  539. let previousPosition, nextPosition;
  540. expect( value.item.data ).to.equal( expected.data );
  541. expect( Array.from( value.item.getAttributes() ) ).to.deep.equal( expected.attrs );
  542. expect( value.length ).to.equal( value.item.data.length );
  543. if ( options.direction == 'backward' ) {
  544. previousPosition = Position._createAfter( value.item );
  545. nextPosition = Position._createBefore( value.item );
  546. } else {
  547. previousPosition = Position._createBefore( value.item );
  548. nextPosition = Position._createAfter( value.item );
  549. }
  550. expect( value.previousPosition ).to.deep.equal( previousPosition );
  551. expect( value.nextPosition ).to.deep.equal( nextPosition );
  552. }
  553. function expectStart( value, expected, options = {} ) {
  554. let previousPosition, nextPosition;
  555. expect( value.item ).to.equal( expected.item );
  556. expect( value.length ).to.equal( 1 );
  557. if ( options.direction == 'backward' ) {
  558. previousPosition = Position._createAfter( value.item );
  559. nextPosition = Position._createBefore( value.item );
  560. } else {
  561. previousPosition = Position._createBefore( value.item );
  562. nextPosition = Position._createAt( value.item, 0 );
  563. }
  564. if ( options.shallow ) {
  565. expect( value.previousPosition ).to.deep.equal( previousPosition );
  566. } else {
  567. expect( value.nextPosition ).to.deep.equal( nextPosition );
  568. }
  569. }
  570. function expectEnd( value, expected, options = {} ) {
  571. let previousPosition, nextPosition;
  572. expect( value.item ).to.equal( expected.item );
  573. expect( value.length ).to.be.undefined;
  574. if ( options.direction == 'backward' ) {
  575. previousPosition = Position._createAfter( value.item );
  576. nextPosition = Position._createAt( value.item, value.item.maxOffset );
  577. } else {
  578. previousPosition = Position._createAt( value.item, value.item.maxOffset );
  579. nextPosition = Position._createAfter( value.item );
  580. }
  581. expect( value.previousPosition ).to.deep.equal( previousPosition );
  582. expect( value.nextPosition ).to.deep.equal( nextPosition );
  583. }