@@ -13,6 +13,7 @@ import {ListItemNode, ListNode} from '@lexical/list';
13
13
import { TableCellNode , TableNode , TableRowNode } from '@lexical/table' ;
14
14
15
15
import {
16
+ $getSelection ,
16
17
$isRangeSelection ,
17
18
createEditor ,
18
19
DecoratorNode ,
@@ -29,14 +30,14 @@ import {
29
30
TextNode ,
30
31
} from 'lexical' ;
31
32
32
- import {
33
- CreateEditorArgs ,
34
- HTMLConfig ,
35
- LexicalNodeReplacement ,
36
- } from '../../LexicalEditor' ;
33
+ import { CreateEditorArgs , HTMLConfig , LexicalNodeReplacement , } from '../../LexicalEditor' ;
37
34
import { resetRandomKey } from '../../LexicalUtils' ;
38
35
import { HeadingNode } from "@lexical/rich-text/LexicalHeadingNode" ;
39
36
import { QuoteNode } from "@lexical/rich-text/LexicalQuoteNode" ;
37
+ import { DetailsNode } from "@lexical/rich-text/LexicalDetailsNode" ;
38
+ import { EditorUiContext } from "../../../../ui/framework/core" ;
39
+ import { EditorUIManager } from "../../../../ui/framework/manager" ;
40
+ import { turtle } from "@codemirror/legacy-modes/mode/turtle" ;
40
41
41
42
42
43
type TestEnv = {
@@ -420,6 +421,7 @@ const DEFAULT_NODES: NonNullable<ReadonlyArray<Klass<LexicalNode> | LexicalNodeR
420
421
TableRowNode ,
421
422
AutoLinkNode ,
422
423
LinkNode ,
424
+ DetailsNode ,
423
425
TestElementNode ,
424
426
TestSegmentedNode ,
425
427
TestExcludeFromCopyElementNode ,
@@ -451,6 +453,7 @@ export function createTestEditor(
451
453
...config ,
452
454
nodes : DEFAULT_NODES . concat ( customNodes ) ,
453
455
} ) ;
456
+
454
457
return editor ;
455
458
}
456
459
@@ -465,6 +468,48 @@ export function createTestHeadlessEditor(
465
468
} ) ;
466
469
}
467
470
471
+ export function createTestContext ( ) : EditorUiContext {
472
+
473
+ const container = document . createElement ( 'div' ) ;
474
+ document . body . appendChild ( container ) ;
475
+
476
+ const scrollWrap = document . createElement ( 'div' ) ;
477
+ const editorDOM = document . createElement ( 'div' ) ;
478
+ editorDOM . setAttribute ( 'contenteditable' , 'true' ) ;
479
+
480
+ scrollWrap . append ( editorDOM ) ;
481
+ container . append ( scrollWrap ) ;
482
+
483
+ const editor = createTestEditor ( {
484
+ namespace : 'testing' ,
485
+ theme : { } ,
486
+ } ) ;
487
+
488
+ editor . setRootElement ( editorDOM ) ;
489
+
490
+ const context = {
491
+ containerDOM : container ,
492
+ editor : editor ,
493
+ editorDOM : editorDOM ,
494
+ error ( text : string | Error ) : void {
495
+ } ,
496
+ manager : new EditorUIManager ( ) ,
497
+ options : { } ,
498
+ scrollDOM : scrollWrap ,
499
+ translate ( text : string ) : string {
500
+ return "" ;
501
+ }
502
+ } ;
503
+
504
+ context . manager . setContext ( context ) ;
505
+
506
+ return context ;
507
+ }
508
+
509
+ export function destroyFromContext ( context : EditorUiContext ) {
510
+ context . containerDOM . remove ( ) ;
511
+ }
512
+
468
513
export function $assertRangeSelection ( selection : unknown ) : RangeSelection {
469
514
if ( ! $isRangeSelection ( selection ) ) {
470
515
throw new Error ( `Expected RangeSelection, got ${ selection } ` ) ;
@@ -715,6 +760,61 @@ export function expectHtmlToBeEqual(expected: string, actual: string): void {
715
760
expect ( formatHtml ( expected ) ) . toBe ( formatHtml ( actual ) ) ;
716
761
}
717
762
763
+ type nodeTextShape = {
764
+ text : string ;
765
+ } ;
766
+
767
+ type nodeShape = {
768
+ type : string ;
769
+ children ?: ( nodeShape | nodeTextShape ) [ ] ;
770
+ }
771
+
772
+ export function getNodeShape ( node : SerializedLexicalNode ) : nodeShape | nodeTextShape {
773
+ // @ts -ignore
774
+ const children : SerializedLexicalNode [ ] = ( node . children || [ ] ) ;
775
+
776
+ const shape : nodeShape = {
777
+ type : node . type ,
778
+ } ;
779
+
780
+ if ( shape . type === 'text' ) {
781
+ // @ts -ignore
782
+ return { text : node . text }
783
+ }
784
+
785
+ if ( children . length > 0 ) {
786
+ shape . children = children . map ( c => getNodeShape ( c ) ) ;
787
+ }
788
+
789
+ return shape ;
790
+ }
791
+
792
+ export function expectNodeShapeToMatch ( editor : LexicalEditor , expected : nodeShape [ ] ) {
793
+ const json = editor . getEditorState ( ) . toJSON ( ) ;
794
+ const shape = getNodeShape ( json . root ) as nodeShape ;
795
+ expect ( shape . children ) . toMatchObject ( expected ) ;
796
+ }
797
+
718
798
function formatHtml ( s : string ) : string {
719
799
return s . replace ( / > \s + < / g, '><' ) . replace ( / \s * \n \s * / g, ' ' ) . trim ( ) ;
800
+ }
801
+
802
+ export function dispatchKeydownEventForNode ( node : LexicalNode , editor : LexicalEditor , key : string ) {
803
+ const nodeDomEl = editor . getElementByKey ( node . getKey ( ) ) ;
804
+ const event = new KeyboardEvent ( 'keydown' , {
805
+ bubbles : true ,
806
+ cancelable : true ,
807
+ key,
808
+ } ) ;
809
+ nodeDomEl ?. dispatchEvent ( event ) ;
810
+ editor . commitUpdates ( ) ;
811
+ }
812
+
813
+ export function dispatchKeydownEventForSelectedNode ( editor : LexicalEditor , key : string ) {
814
+ editor . getEditorState ( ) . read ( ( ) : void => {
815
+ const node = $getSelection ( ) ?. getNodes ( ) [ 0 ] || null ;
816
+ if ( node ) {
817
+ dispatchKeydownEventForNode ( node , editor , key ) ;
818
+ }
819
+ } ) ;
720
820
}
0 commit comments