11/* eslint-disable no-unused-expressions */
2- import { fixture , expect , html , oneEvent } from '@open-wc/testing' ;
2+ import { fixture , expect , html } from '@open-wc/testing' ;
3+ import { SinonSpy , spy } from 'sinon' ;
34import { AddDataObjectDialog } from './add-data-object-dialog.js' ;
45
5- const cdClasses = [ 'WYE' , 'DEL' , 'SAV' ] ;
6+ const cdClasses = [ 'WYE' , 'DEL' , 'SAV' , 'ORG' ] ;
7+ const tree = {
8+ TestDO1 : {
9+ presCond : 'Omulti' ,
10+ type : 'WYE' ,
11+ } ,
12+ Beh : {
13+ presCond : '0' ,
14+ type : 'ORG' ,
15+ } ,
16+ AnotherDO1 : {
17+ presCond : 'Omulti' ,
18+ type : 'DEL' ,
19+ } ,
20+ } ;
621
7- window . customElements . define ( 'add-data-object-dialog' , AddDataObjectDialog ) ;
22+ customElements . define ( 'add-data-object-dialog' , AddDataObjectDialog ) ;
823
924describe ( 'AddDataObjectDialog' , ( ) => {
1025 let dialog : AddDataObjectDialog ;
26+ let confirmSpy : SinonSpy ;
27+
1128 beforeEach ( async ( ) => {
29+ confirmSpy = spy ( ) ;
30+
1231 dialog = await fixture (
1332 html `< add-data-object-dialog
1433 .cdClasses =${ cdClasses }
34+ .tree =${ tree }
35+ .onConfirm=${ confirmSpy }
1536 > </ add-data-object-dialog > `
1637 ) ;
17- document . body . prepend ( dialog ) ;
1838 } ) ;
1939
2040 afterEach ( async ( ) => {
@@ -32,48 +52,233 @@ describe('AddDataObjectDialog', () => {
3252 } ) ;
3353 } ) ;
3454
35- it ( 'validates required fields ' , async ( ) => {
55+ it ( 'should call onConfirm for valid form ' , async ( ) => {
3656 dialog . show ( ) ;
37- expect ( dialog . cdcType . error ) . to . be . false ;
38- expect ( dialog . doName . error ) . to . be . false ;
39- const form = dialog . shadowRoot ! . querySelector ( 'form' ) ! ;
40- form . dispatchEvent (
41- new Event ( 'submit' , { bubbles : true , cancelable : true } )
42- ) ;
4357 await dialog . updateComplete ;
44- expect ( dialog . cdcType . error ) . to . be . true ;
45- expect ( dialog . doName . error ) . to . be . true ;
46- } ) ;
4758
48- it ( 'dispatches add-data-object event on valid submit' , async ( ) => {
49- dialog . show ( ) ;
50- const [ firstCdClass ] = cdClasses ;
51- dialog . cdcType . value = firstCdClass ;
52- dialog . doName . value = 'TestDO' ;
59+ const type = 'WYE' ;
60+ const doName = 'TestDO2' ;
61+
62+ dialog . cdcType . value = type ;
63+ dialog . doName . value = doName ;
5364 await dialog . updateComplete ;
54- setTimeout ( ( ) => {
55- dialog
56- . shadowRoot ! . querySelector ( 'form' ) !
57- . dispatchEvent (
58- new Event ( 'submit' , { bubbles : true , cancelable : true } )
59- ) ;
60- } ) ;
61- const event = await oneEvent ( dialog , 'add-data-object' ) ;
62- expect ( event ) . to . exist ;
63- expect ( event . detail ) . to . deep . equal ( {
64- cdcType : cdClasses [ 0 ] ,
65- doName : 'TestDO' ,
65+
66+ const form = dialog . shadowRoot ?. querySelector ( 'form' ) as HTMLFormElement ;
67+ const submitEvent = new Event ( 'submit' , {
68+ bubbles : true ,
69+ cancelable : true ,
6670 } ) ;
71+ form . dispatchEvent ( submitEvent ) ;
72+
73+ await dialog . updateComplete ;
74+
75+ expect ( confirmSpy . callCount ) . to . equal ( 1 ) ;
76+ expect ( confirmSpy . calledWith ( type , doName , null ) ) . to . be . true ;
6777 } ) ;
6878
6979 it ( 'clears form fields on close' , async ( ) => {
7080 dialog . show ( ) ;
7181 const [ firstCdClass ] = cdClasses ;
7282 dialog . cdcType . value = firstCdClass ;
7383 dialog . doName . value = 'TestDO' ;
84+ dialog . namespace . value = 'CustomNamespace' ;
7485 await dialog . updateComplete ;
7586 dialog . close ( ) ;
7687 expect ( dialog . cdcType . value ) . to . equal ( '' ) ;
7788 expect ( dialog . doName . value ) . to . equal ( '' ) ;
7889 } ) ;
90+
91+ describe ( 'input validation' , ( ) => {
92+ beforeEach ( ( ) => {
93+ dialog . show ( ) ;
94+ } ) ;
95+
96+ it ( 'validates required fields when form is empty' , async ( ) => {
97+ expect ( dialog . cdcType . error ) . to . be . false ;
98+ expect ( dialog . doName . error ) . to . be . false ;
99+
100+ const form = dialog . shadowRoot ! . querySelector ( 'form' ) ! ;
101+ form . dispatchEvent (
102+ new Event ( 'submit' , { bubbles : true , cancelable : true } )
103+ ) ;
104+ await dialog . updateComplete ;
105+
106+ expect ( dialog . cdcType . error ) . to . be . true ;
107+ expect ( dialog . cdcType . errorText ) . to . equal (
108+ 'Please select a common data class.'
109+ ) ;
110+ expect ( dialog . doName . error ) . to . be . true ;
111+ expect ( dialog . doName . errorText ) . to . equal ( 'Not a valid DO name.' ) ;
112+ expect ( confirmSpy . callCount ) . to . equal ( 0 ) ;
113+ } ) ;
114+
115+ it ( 'validates DO name pattern (must start with uppercase letter)' , async ( ) => {
116+ dialog . cdcType . value = 'WYE' ;
117+ dialog . doName . value = 'testDO' ;
118+
119+ const form = dialog . shadowRoot ! . querySelector ( 'form' ) ! ;
120+ form . dispatchEvent (
121+ new Event ( 'submit' , { bubbles : true , cancelable : true } )
122+ ) ;
123+ await dialog . updateComplete ;
124+
125+ expect ( dialog . doName . error ) . to . be . true ;
126+ expect ( dialog . doName . errorText ) . to . equal ( 'Not a valid DO name.' ) ;
127+ expect ( confirmSpy . callCount ) . to . equal ( 0 ) ;
128+ } ) ;
129+
130+ it ( 'validates DO name pattern (invalid characters)' , async ( ) => {
131+ dialog . cdcType . value = 'WYE' ;
132+ dialog . doName . value = 'Test-DO' ;
133+
134+ const form = dialog . shadowRoot ! . querySelector ( 'form' ) ! ;
135+ form . dispatchEvent (
136+ new Event ( 'submit' , { bubbles : true , cancelable : true } )
137+ ) ;
138+ await dialog . updateComplete ;
139+
140+ expect ( dialog . doName . error ) . to . be . true ;
141+ expect ( dialog . doName . errorText ) . to . equal ( 'Not a valid DO name.' ) ;
142+ expect ( confirmSpy . callCount ) . to . equal ( 0 ) ;
143+ } ) ;
144+
145+ it ( 'should set "DO name already in use" error' , async ( ) => {
146+ dialog . cdcType . value = 'ORG' ;
147+ dialog . doName . value = 'Beh' ;
148+
149+ const form = dialog . shadowRoot ! . querySelector ( 'form' ) ! ;
150+ form . dispatchEvent (
151+ new Event ( 'submit' , { bubbles : true , cancelable : true } )
152+ ) ;
153+ await dialog . updateComplete ;
154+
155+ expect ( confirmSpy . callCount ) . to . equal ( 0 ) ;
156+ expect ( dialog . doName . error ) . to . be . true ;
157+ expect ( dialog . doName . errorText ) . to . equal ( 'DO name already in use' ) ;
158+ } ) ;
159+
160+ it ( 'should set "CDC type invalid for this DO" error for existing multi DO with different type' , async ( ) => {
161+ dialog . cdcType . value = 'ORG' ;
162+ dialog . doName . value = 'TestDO2' ;
163+
164+ dialog . cdcType . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
165+ dialog . doName . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
166+
167+ await new Promise < void > ( resolve => {
168+ setTimeout ( resolve , 400 ) ;
169+ } ) ;
170+
171+ const form = dialog . shadowRoot ! . querySelector ( 'form' ) ! ;
172+ form . dispatchEvent (
173+ new Event ( 'submit' , { bubbles : true , cancelable : true } )
174+ ) ;
175+ await dialog . updateComplete ;
176+
177+ expect ( confirmSpy . callCount ) . to . equal ( 0 ) ;
178+ expect ( dialog . cdcType . error ) . to . be . true ;
179+ expect ( dialog . cdcType . errorText ) . to . equal ( 'CDC type invalid for this DO' ) ;
180+ } ) ;
181+
182+ it ( 'should require custom namespace for new DO names' , async ( ) => {
183+ dialog . cdcType . value = 'ORG' ;
184+ dialog . doName . value = 'NewDOName' ;
185+
186+ dialog . cdcType . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
187+ dialog . doName . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
188+
189+ await new Promise < void > ( resolve => {
190+ setTimeout ( resolve , 400 ) ;
191+ } ) ;
192+
193+ expect ( dialog . namespace . disabled ) . to . be . false ;
194+
195+ const form = dialog . shadowRoot ! . querySelector ( 'form' ) ! ;
196+ form . dispatchEvent (
197+ new Event ( 'submit' , { bubbles : true , cancelable : true } )
198+ ) ;
199+ await dialog . updateComplete ;
200+
201+ expect ( confirmSpy . callCount ) . to . equal ( 0 ) ;
202+ expect ( dialog . namespace . error ) . to . be . true ;
203+ expect ( dialog . namespace . errorText ) . to . equal ( 'Custom namespace required.' ) ;
204+ } ) ;
205+
206+ it ( 'should pass validation with custom namespace' , async ( ) => {
207+ dialog . cdcType . value = 'ORG' ;
208+ dialog . doName . value = 'NewDOName' ;
209+
210+ dialog . cdcType . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
211+ dialog . doName . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
212+
213+ await new Promise < void > ( resolve => {
214+ setTimeout ( resolve , 400 ) ;
215+ } ) ;
216+
217+ dialog . namespace . value = 'CustomNamespace' ;
218+
219+ const form = dialog . shadowRoot ! . querySelector ( 'form' ) ! ;
220+ form . dispatchEvent (
221+ new Event ( 'submit' , { bubbles : true , cancelable : true } )
222+ ) ;
223+ await dialog . updateComplete ;
224+
225+ expect ( confirmSpy . callCount ) . to . equal ( 1 ) ;
226+ expect ( confirmSpy . calledWith ( 'ORG' , 'NewDOName' , 'CustomNamespace' ) ) . to . be
227+ . true ;
228+ } ) ;
229+
230+ it ( 'should pass validation for existing multi DO with correct type' , async ( ) => {
231+ dialog . cdcType . value = 'WYE' ;
232+ dialog . doName . value = 'TestDO2' ;
233+
234+ const form = dialog . shadowRoot ! . querySelector ( 'form' ) ! ;
235+ form . dispatchEvent (
236+ new Event ( 'submit' , { bubbles : true , cancelable : true } )
237+ ) ;
238+ await dialog . updateComplete ;
239+
240+ expect ( confirmSpy . callCount ) . to . equal ( 1 ) ;
241+ expect ( confirmSpy . calledWith ( 'WYE' , 'TestDO2' , null ) ) . to . be . true ;
242+ } ) ;
243+
244+ it ( 'should reset error states when valid input is provided' , async ( ) => {
245+ const form = dialog . shadowRoot ! . querySelector ( 'form' ) ! ;
246+ form . dispatchEvent (
247+ new Event ( 'submit' , { bubbles : true , cancelable : true } )
248+ ) ;
249+ await dialog . updateComplete ;
250+
251+ expect ( dialog . cdcType . error ) . to . be . true ;
252+ expect ( dialog . doName . error ) . to . be . true ;
253+
254+ dialog . cdcType . value = 'WYE' ;
255+ dialog . cdcType . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
256+
257+ dialog . doName . value = 'ValidDO' ;
258+ dialog . doName . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
259+
260+ await dialog . updateComplete ;
261+
262+ expect ( dialog . cdcType . error ) . to . be . false ;
263+ expect ( dialog . cdcType . errorText ) . to . equal ( '' ) ;
264+ expect ( dialog . doName . error ) . to . be . false ;
265+ expect ( dialog . doName . errorText ) . to . equal ( '' ) ;
266+ } ) ;
267+
268+ it ( 'should disable namespace field initially and for existing DOs' , async ( ) => {
269+ expect ( dialog . namespace . disabled ) . to . be . true ;
270+
271+ dialog . cdcType . value = 'WYE' ;
272+ dialog . doName . value = 'TestDO2' ;
273+
274+ dialog . cdcType . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
275+ dialog . doName . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
276+
277+ await new Promise < void > ( resolve => {
278+ setTimeout ( resolve , 400 ) ;
279+ } ) ;
280+
281+ expect ( dialog . namespace . disabled ) . to . be . true ;
282+ } ) ;
283+ } ) ;
79284} ) ;
0 commit comments