@@ -16,23 +16,41 @@ function createStubWriteAdapter(): WriteAdapter {
1616 return { write : vi . fn ( ) , insertStructured : vi . fn ( ) , replaceStructured : vi . fn ( ) } as unknown as WriteAdapter ;
1717}
1818
19+ function exec ( input : unknown ) : void {
20+ executeInsert ( createStubSelectionAdapter ( ) , createStubWriteAdapter ( ) , input as InsertInput ) ;
21+ }
22+
23+ // ---------------------------------------------------------------------------
24+ // Input shape discrimination
25+ // ---------------------------------------------------------------------------
26+
27+ describe ( 'executeInsert: input shape' , ( ) => {
28+ it ( 'rejects non-object input' , ( ) => {
29+ expect ( ( ) => exec ( null ) ) . toThrow ( 'non-null object' ) ;
30+ expect ( ( ) => exec ( 'hello' ) ) . toThrow ( 'non-null object' ) ;
31+ expect ( ( ) => exec ( 42 ) ) . toThrow ( 'non-null object' ) ;
32+ } ) ;
33+
34+ it ( 'rejects input with neither value nor content' , ( ) => {
35+ expect ( ( ) => exec ( { } ) ) . toThrow ( 'either "value"' ) ;
36+ } ) ;
37+
38+ it ( 'rejects input with both value and content' , ( ) => {
39+ expect ( ( ) => exec ( { value : 'hello' , content : { blocks : [ ] } } ) ) . toThrow ( 'not both' ) ;
40+ } ) ;
41+ } ) ;
42+
1943// ---------------------------------------------------------------------------
20- // ref validation
44+ // Text insert: ref validation
2145// ---------------------------------------------------------------------------
2246
2347describe ( 'executeInsert: ref validation' , ( ) => {
2448 it ( 'rejects empty string ref' , ( ) => {
25- const input : InsertInput = { value : 'hello' , ref : '' } as unknown as InsertInput ;
26- expect ( ( ) => executeInsert ( createStubSelectionAdapter ( ) , createStubWriteAdapter ( ) , input ) ) . toThrow (
27- 'ref must be a non-empty string' ,
28- ) ;
49+ expect ( ( ) => exec ( { value : 'hello' , ref : '' } ) ) . toThrow ( 'ref must be a non-empty string' ) ;
2950 } ) ;
3051
3152 it ( 'rejects non-string ref' , ( ) => {
32- const input = { value : 'hello' , ref : 42 } as unknown as InsertInput ;
33- expect ( ( ) => executeInsert ( createStubSelectionAdapter ( ) , createStubWriteAdapter ( ) , input ) ) . toThrow (
34- 'ref must be a non-empty string' ,
35- ) ;
53+ expect ( ( ) => exec ( { value : 'hello' , ref : 42 } ) ) . toThrow ( 'ref must be a non-empty string' ) ;
3654 } ) ;
3755
3856 it ( 'does not reject undefined ref (untargeted insert is valid)' , ( ) => {
@@ -41,3 +59,70 @@ describe('executeInsert: ref validation', () => {
4159 expect ( ( ) => executeInsert ( createStubSelectionAdapter ( ) , writeAdapter , { value : 'hello' } ) ) . not . toThrow ( ) ;
4260 } ) ;
4361} ) ;
62+
63+ // ---------------------------------------------------------------------------
64+ // Text insert: target/ref mutual exclusivity
65+ // ---------------------------------------------------------------------------
66+
67+ describe ( 'executeInsert: target/ref mutual exclusivity' , ( ) => {
68+ it ( 'rejects input with both target and ref' , ( ) => {
69+ const target = {
70+ kind : 'selection' ,
71+ start : { kind : 'text' , blockId : 'b1' , offset : 0 } ,
72+ end : { kind : 'text' , blockId : 'b1' , offset : 0 } ,
73+ } ;
74+ expect ( ( ) => exec ( { value : 'hello' , target, ref : 'r1' } ) ) . toThrow ( 'either "target" or "ref", not both' ) ;
75+ } ) ;
76+ } ) ;
77+
78+ // ---------------------------------------------------------------------------
79+ // Text insert: content type validation
80+ // ---------------------------------------------------------------------------
81+
82+ describe ( 'executeInsert: content type validation' , ( ) => {
83+ it ( 'rejects invalid content type' , ( ) => {
84+ expect ( ( ) => exec ( { value : 'hello' , type : 'pdf' } ) ) . toThrow ( 'text, markdown, html' ) ;
85+ } ) ;
86+
87+ it ( 'rejects non-string content type' , ( ) => {
88+ expect ( ( ) => exec ( { value : 'hello' , type : 123 } ) ) . toThrow ( 'text, markdown, html' ) ;
89+ } ) ;
90+ } ) ;
91+
92+ // ---------------------------------------------------------------------------
93+ // Text insert: value validation
94+ // ---------------------------------------------------------------------------
95+
96+ describe ( 'executeInsert: value validation' , ( ) => {
97+ it ( 'rejects non-string value' , ( ) => {
98+ expect ( ( ) => exec ( { value : 42 } ) ) . toThrow ( 'value must be a string' ) ;
99+ } ) ;
100+ } ) ;
101+
102+ // ---------------------------------------------------------------------------
103+ // Text insert: unknown fields
104+ // ---------------------------------------------------------------------------
105+
106+ describe ( 'executeInsert: unknown fields' , ( ) => {
107+ it ( 'rejects unknown fields on text input' , ( ) => {
108+ expect ( ( ) => exec ( { value : 'hello' , bogus : true } ) ) . toThrow ( 'bogus' ) ;
109+ } ) ;
110+ } ) ;
111+
112+ // ---------------------------------------------------------------------------
113+ // Structural insert: validation
114+ // ---------------------------------------------------------------------------
115+
116+ describe ( 'executeInsert: structural input validation' , ( ) => {
117+ it ( 'rejects structural input with text-only "type" field' , ( ) => {
118+ expect ( ( ) => exec ( { content : { blocks : [ ] } , type : 'markdown' } ) ) . toThrow ( '"type" field is only valid' ) ;
119+ } ) ;
120+
121+ it ( 'rejects invalid placement value' , ( ) => {
122+ expect ( ( ) => exec ( { content : { blocks : [ ] } , placement : 'middle' } ) ) . toThrow ( 'before, after' ) ;
123+ } ) ;
124+
125+ it ( 'rejects text-only fields on structural input' , ( ) => {
126+ expect ( ( ) => exec ( { content : { blocks : [ ] } , ref : 'r1' } ) ) . toThrow ( ) ;
127+ } ) ;
128+ } ) ;
0 commit comments