Skip to content

Commit 6165643

Browse files
authored
Merge pull request #14 from openscd/feature/do-user-defined-namespace
feature: do user defined namespace
2 parents 9c9bebe + 0adacb3 commit 6165643

File tree

5 files changed

+436
-48
lines changed

5 files changed

+436
-48
lines changed
Lines changed: 236 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,40 @@
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';
34
import { 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

924
describe('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

Comments
 (0)