@omicronenergy/oscd-scl-dialogs 0.0.12 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +4 -2
- package/custom-elements.json +265 -1
- package/dist/wizards/connectedap.js +6 -3
- package/dist/wizards/connectedap.js.map +1 -1
- package/dist/wizards/dataset.d.ts +2 -0
- package/dist/wizards/dataset.js +86 -0
- package/dist/wizards/dataset.js.map +1 -0
- package/dist/wizards/dataset.spec.d.ts +1 -0
- package/dist/wizards/dataset.spec.js +240 -0
- package/dist/wizards/dataset.spec.js.map +1 -0
- package/dist/wizards/gsecontrol.d.ts +2 -0
- package/dist/wizards/gsecontrol.js +86 -0
- package/dist/wizards/gsecontrol.js.map +1 -0
- package/dist/wizards/gsecontrol.spec.d.ts +1 -0
- package/dist/wizards/gsecontrol.spec.js +216 -0
- package/dist/wizards/gsecontrol.spec.js.map +1 -0
- package/dist/wizards/patterns.d.ts +2 -0
- package/dist/wizards/patterns.js +2 -0
- package/dist/wizards/patterns.js.map +1 -1
- package/dist/wizards/sampledvaluecontrol.d.ts +2 -0
- package/dist/wizards/sampledvaluecontrol.js +115 -0
- package/dist/wizards/sampledvaluecontrol.js.map +1 -0
- package/dist/wizards/sampledvaluecontrol.spec.d.ts +1 -0
- package/dist/wizards/sampledvaluecontrol.spec.js +227 -0
- package/dist/wizards/sampledvaluecontrol.spec.js.map +1 -0
- package/dist/wizards/smvopts.d.ts +2 -0
- package/dist/wizards/smvopts.js +43 -0
- package/dist/wizards/smvopts.js.map +1 -0
- package/dist/wizards/smvopts.spec.d.ts +1 -0
- package/dist/wizards/smvopts.spec.js +193 -0
- package/dist/wizards/smvopts.spec.js.map +1 -0
- package/dist/wizards/wizards.js +14 -2
- package/dist/wizards/wizards.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
|
2
|
+
import { expect, fixture } from '@open-wc/testing';
|
|
3
|
+
import { html } from 'lit';
|
|
4
|
+
import { editDataSetWizard } from './dataset.js';
|
|
5
|
+
import { XMLEditor } from '@openscd/oscd-editor';
|
|
6
|
+
import { SclTextField } from '@openenergytools/scl-text-field';
|
|
7
|
+
import { SelectionList } from '@openenergytools/filterable-lists/dist/SelectionList.js';
|
|
8
|
+
if (!customElements.get('scl-text-field')) {
|
|
9
|
+
customElements.define('scl-text-field', SclTextField);
|
|
10
|
+
}
|
|
11
|
+
if (!customElements.get('selection-list')) {
|
|
12
|
+
customElements.define('selection-list', SelectionList);
|
|
13
|
+
}
|
|
14
|
+
const xmlParser = new DOMParser();
|
|
15
|
+
function createSclDoc() {
|
|
16
|
+
return xmlParser.parseFromString(`
|
|
17
|
+
<SCL xmlns="http://www.iec.ch/61850/2003/SCL">
|
|
18
|
+
<IED name="IED1">
|
|
19
|
+
<AccessPoint name="AP1">
|
|
20
|
+
<Server>
|
|
21
|
+
<LDevice inst="LD1">
|
|
22
|
+
<LN0 lnClass="LLN0" inst="" lnType="LLN0_Type">
|
|
23
|
+
<DataSet name="DS1" desc="Data set 1">
|
|
24
|
+
<FCDA ldInst="LD1" lnClass="LLN0" doName="Beh" daName="stVal" fc="ST" />
|
|
25
|
+
<FCDA ldInst="LD1" lnClass="LLN0" doName="Beh" daName="q" fc="ST" />
|
|
26
|
+
<FCDA ldInst="LD1" lnClass="MMXU" lnInst="1" doName="TotW" fc="MX" />
|
|
27
|
+
</DataSet>
|
|
28
|
+
<DataSet name="DS2" />
|
|
29
|
+
</LN0>
|
|
30
|
+
</LDevice>
|
|
31
|
+
</Server>
|
|
32
|
+
</AccessPoint>
|
|
33
|
+
</IED>
|
|
34
|
+
</SCL>
|
|
35
|
+
`, 'application/xml');
|
|
36
|
+
}
|
|
37
|
+
async function renderContent(wizard) {
|
|
38
|
+
const content = await fixture(html `<form>${wizard.content}</form>`);
|
|
39
|
+
const nameField = content.querySelector('scl-text-field[label="name"]');
|
|
40
|
+
const descField = content.querySelector('scl-text-field[label="desc"]');
|
|
41
|
+
const fcdaList = content.querySelector('selection-list#fcda-list');
|
|
42
|
+
expect(nameField).to.exist;
|
|
43
|
+
expect(descField).to.exist;
|
|
44
|
+
return {
|
|
45
|
+
content,
|
|
46
|
+
nameField,
|
|
47
|
+
descField,
|
|
48
|
+
fcdaList,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
describe('DataSet edit wizard', () => {
|
|
52
|
+
let xmlEditor;
|
|
53
|
+
let renderedContainer;
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
xmlEditor = new XMLEditor();
|
|
56
|
+
});
|
|
57
|
+
afterEach(() => {
|
|
58
|
+
if (renderedContainer) {
|
|
59
|
+
renderedContainer.remove();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
it('returns a wizard with correct title and 3 content items', () => {
|
|
63
|
+
const scl = createSclDoc();
|
|
64
|
+
const element = scl.querySelector('DataSet[name="DS1"]');
|
|
65
|
+
const wizard = editDataSetWizard(element);
|
|
66
|
+
expect(wizard.title).to.equal('Edit DataSet');
|
|
67
|
+
expect(wizard.primary).to.exist;
|
|
68
|
+
expect(wizard.primary.icon).to.equal('edit');
|
|
69
|
+
expect(wizard.primary.label).to.equal('save');
|
|
70
|
+
expect(wizard.content).to.have.lengthOf(3);
|
|
71
|
+
});
|
|
72
|
+
it('populates fields with current attribute values', async () => {
|
|
73
|
+
const scl = createSclDoc();
|
|
74
|
+
const element = scl.querySelector('DataSet[name="DS1"]');
|
|
75
|
+
const wizard = editDataSetWizard(element);
|
|
76
|
+
const fields = await renderContent(wizard);
|
|
77
|
+
renderedContainer = fields.content;
|
|
78
|
+
expect(fields.nameField.value).to.equal('DS1');
|
|
79
|
+
expect(fields.descField.value).to.equal('Data set 1');
|
|
80
|
+
});
|
|
81
|
+
it('renders name field as disabled', async () => {
|
|
82
|
+
const scl = createSclDoc();
|
|
83
|
+
const element = scl.querySelector('DataSet[name="DS1"]');
|
|
84
|
+
const wizard = editDataSetWizard(element);
|
|
85
|
+
const fields = await renderContent(wizard);
|
|
86
|
+
renderedContainer = fields.content;
|
|
87
|
+
expect(fields.nameField.disabled).to.be.true;
|
|
88
|
+
});
|
|
89
|
+
it('renders the FCDA selection list', async () => {
|
|
90
|
+
const scl = createSclDoc();
|
|
91
|
+
const element = scl.querySelector('DataSet[name="DS1"]');
|
|
92
|
+
const wizard = editDataSetWizard(element);
|
|
93
|
+
const fields = await renderContent(wizard);
|
|
94
|
+
renderedContainer = fields.content;
|
|
95
|
+
expect(fields.fcdaList).to.exist;
|
|
96
|
+
expect(fields.fcdaList.items).to.have.lengthOf(3);
|
|
97
|
+
expect(fields.fcdaList.items[0].selected).to.be.true;
|
|
98
|
+
expect(fields.fcdaList.items[1].selected).to.be.true;
|
|
99
|
+
expect(fields.fcdaList.items[2].selected).to.be.true;
|
|
100
|
+
});
|
|
101
|
+
it('renders FCDA labels with ldInst, lnClass, doName, daName, fc', async () => {
|
|
102
|
+
const scl = createSclDoc();
|
|
103
|
+
const element = scl.querySelector('DataSet[name="DS1"]');
|
|
104
|
+
const wizard = editDataSetWizard(element);
|
|
105
|
+
const fields = await renderContent(wizard);
|
|
106
|
+
renderedContainer = fields.content;
|
|
107
|
+
expect(fields.fcdaList.items[0].headline).to.equal('LD1.LLN0.Beh.stVal.[ST]');
|
|
108
|
+
expect(fields.fcdaList.items[1].headline).to.equal('LD1.LLN0.Beh.q.[ST]');
|
|
109
|
+
expect(fields.fcdaList.items[2].headline).to.equal('LD1.MMXU1.TotW.[MX]');
|
|
110
|
+
});
|
|
111
|
+
it('returns [] when no changes are made', async () => {
|
|
112
|
+
const scl = createSclDoc();
|
|
113
|
+
const element = scl.querySelector('DataSet[name="DS1"]');
|
|
114
|
+
const wizard = editDataSetWizard(element);
|
|
115
|
+
const fields = await renderContent(wizard);
|
|
116
|
+
renderedContainer = fields.content;
|
|
117
|
+
const edits = wizard.primary.action([fields.nameField, fields.descField], renderedContainer);
|
|
118
|
+
expect(edits).to.have.lengthOf(0);
|
|
119
|
+
});
|
|
120
|
+
it('returns SetAttributes with changed desc', async () => {
|
|
121
|
+
const scl = createSclDoc();
|
|
122
|
+
const element = scl.querySelector('DataSet[name="DS1"]');
|
|
123
|
+
const wizard = editDataSetWizard(element);
|
|
124
|
+
const fields = await renderContent(wizard);
|
|
125
|
+
renderedContainer = fields.content;
|
|
126
|
+
fields.descField.value = 'Updated description';
|
|
127
|
+
const edits = wizard.primary.action([fields.nameField, fields.descField], renderedContainer);
|
|
128
|
+
expect(edits).to.have.lengthOf(1);
|
|
129
|
+
const edit = edits[0];
|
|
130
|
+
expect(edit.element).to.equal(element);
|
|
131
|
+
expect(edit.attributes.desc).to.equal('Updated description');
|
|
132
|
+
});
|
|
133
|
+
it('applies changed desc to the document', async () => {
|
|
134
|
+
const scl = createSclDoc();
|
|
135
|
+
const element = scl.querySelector('DataSet[name="DS1"]');
|
|
136
|
+
const wizard = editDataSetWizard(element);
|
|
137
|
+
const fields = await renderContent(wizard);
|
|
138
|
+
renderedContainer = fields.content;
|
|
139
|
+
fields.descField.value = 'Updated description';
|
|
140
|
+
const edits = wizard.primary.action([fields.nameField, fields.descField], renderedContainer);
|
|
141
|
+
xmlEditor.commit(edits);
|
|
142
|
+
expect(element.getAttribute('desc')).to.equal('Updated description');
|
|
143
|
+
expect(element.getAttribute('name')).to.equal('DS1');
|
|
144
|
+
});
|
|
145
|
+
it('handles nullable desc — set to null removes attribute', async () => {
|
|
146
|
+
const scl = createSclDoc();
|
|
147
|
+
const element = scl.querySelector('DataSet[name="DS1"]');
|
|
148
|
+
expect(element.getAttribute('desc')).to.equal('Data set 1');
|
|
149
|
+
const wizard = editDataSetWizard(element);
|
|
150
|
+
const fields = await renderContent(wizard);
|
|
151
|
+
renderedContainer = fields.content;
|
|
152
|
+
fields.descField.value = null;
|
|
153
|
+
const edits = wizard.primary.action([fields.nameField, fields.descField], renderedContainer);
|
|
154
|
+
expect(edits).to.have.lengthOf(1);
|
|
155
|
+
const edit = edits[0];
|
|
156
|
+
expect(edit.attributes.desc).to.be.null;
|
|
157
|
+
xmlEditor.commit(edits);
|
|
158
|
+
expect(element.getAttribute('desc')).to.be.null;
|
|
159
|
+
});
|
|
160
|
+
it('handles element with no FCDAs (DS2)', async () => {
|
|
161
|
+
const scl = createSclDoc();
|
|
162
|
+
const element = scl.querySelector('DataSet[name="DS2"]');
|
|
163
|
+
const wizard = editDataSetWizard(element);
|
|
164
|
+
const fields = await renderContent(wizard);
|
|
165
|
+
renderedContainer = fields.content;
|
|
166
|
+
expect(fields.nameField.value).to.equal('DS2');
|
|
167
|
+
expect(fields.descField.value).to.be.null;
|
|
168
|
+
expect(fields.fcdaList).to.exist;
|
|
169
|
+
expect(fields.fcdaList.items).to.have.lengthOf(0);
|
|
170
|
+
});
|
|
171
|
+
it('returns [] when no-attribute element is unchanged', async () => {
|
|
172
|
+
const scl = createSclDoc();
|
|
173
|
+
const element = scl.querySelector('DataSet[name="DS2"]');
|
|
174
|
+
const wizard = editDataSetWizard(element);
|
|
175
|
+
const fields = await renderContent(wizard);
|
|
176
|
+
renderedContainer = fields.content;
|
|
177
|
+
const edits = wizard.primary.action([fields.nameField, fields.descField], renderedContainer);
|
|
178
|
+
expect(edits).to.have.lengthOf(0);
|
|
179
|
+
});
|
|
180
|
+
it('returns Remove edits for deselected FCDAs', async () => {
|
|
181
|
+
const scl = createSclDoc();
|
|
182
|
+
const element = scl.querySelector('DataSet[name="DS1"]');
|
|
183
|
+
const allFcdas = Array.from(element.querySelectorAll('FCDA'));
|
|
184
|
+
expect(allFcdas).to.have.lengthOf(3);
|
|
185
|
+
const wizard = editDataSetWizard(element);
|
|
186
|
+
const fields = await renderContent(wizard);
|
|
187
|
+
renderedContainer = fields.content;
|
|
188
|
+
// Deselect the second FCDA
|
|
189
|
+
fields.fcdaList.items = fields.fcdaList.items.map((item, index) => ({
|
|
190
|
+
...item,
|
|
191
|
+
selected: index !== 1,
|
|
192
|
+
}));
|
|
193
|
+
const edits = wizard.primary.action([fields.nameField, fields.descField], renderedContainer);
|
|
194
|
+
expect(edits).to.have.lengthOf(1);
|
|
195
|
+
const removeEdit = edits[0];
|
|
196
|
+
expect(removeEdit.node).to.equal(allFcdas[1]);
|
|
197
|
+
});
|
|
198
|
+
it('returns both Remove and SetAttributes when desc changed and FCDA deselected', async () => {
|
|
199
|
+
const scl = createSclDoc();
|
|
200
|
+
const element = scl.querySelector('DataSet[name="DS1"]');
|
|
201
|
+
const allFcdas = Array.from(element.querySelectorAll('FCDA'));
|
|
202
|
+
const wizard = editDataSetWizard(element);
|
|
203
|
+
const fields = await renderContent(wizard);
|
|
204
|
+
renderedContainer = fields.content;
|
|
205
|
+
// Deselect the first FCDA
|
|
206
|
+
fields.fcdaList.items = fields.fcdaList.items.map((item, index) => ({
|
|
207
|
+
...item,
|
|
208
|
+
selected: index !== 0,
|
|
209
|
+
}));
|
|
210
|
+
// Also change desc
|
|
211
|
+
fields.descField.value = 'New desc';
|
|
212
|
+
const edits = wizard.primary.action([fields.nameField, fields.descField], renderedContainer);
|
|
213
|
+
expect(edits).to.have.lengthOf(2);
|
|
214
|
+
// Remove edit comes first
|
|
215
|
+
const removeEdit = edits[0];
|
|
216
|
+
expect(removeEdit.node).to.equal(allFcdas[0]);
|
|
217
|
+
// SetAttributes edit comes second
|
|
218
|
+
const setAttrs = edits[1];
|
|
219
|
+
expect(setAttrs.element).to.equal(element);
|
|
220
|
+
expect(setAttrs.attributes.desc).to.equal('New desc');
|
|
221
|
+
});
|
|
222
|
+
it('applies FCDA removal to the document', async () => {
|
|
223
|
+
const scl = createSclDoc();
|
|
224
|
+
const element = scl.querySelector('DataSet[name="DS1"]');
|
|
225
|
+
expect(element.querySelectorAll('FCDA')).to.have.lengthOf(3);
|
|
226
|
+
const wizard = editDataSetWizard(element);
|
|
227
|
+
const fields = await renderContent(wizard);
|
|
228
|
+
renderedContainer = fields.content;
|
|
229
|
+
// Deselect first and third FCDAs
|
|
230
|
+
fields.fcdaList.items = fields.fcdaList.items.map((item, index) => ({
|
|
231
|
+
...item,
|
|
232
|
+
selected: index === 1,
|
|
233
|
+
}));
|
|
234
|
+
const edits = wizard.primary.action([fields.nameField, fields.descField], renderedContainer);
|
|
235
|
+
expect(edits).to.have.lengthOf(2);
|
|
236
|
+
xmlEditor.commit(edits);
|
|
237
|
+
expect(element.querySelectorAll('FCDA')).to.have.lengthOf(1);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
//# sourceMappingURL=dataset.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataset.spec.js","sourceRoot":"","sources":["../../wizards/dataset.spec.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAE3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,yDAAyD,CAAC;AAGxF,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC;IAC1C,cAAc,CAAC,MAAM,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC;AACxD,CAAC;AACD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC;IAC1C,cAAc,CAAC,MAAM,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;AAClC,SAAS,YAAY;IACnB,OAAO,SAAS,CAAC,eAAe,CAC9B;;;;;;;;;;;;;;;;;;;KAmBC,EACD,iBAAiB,CAClB,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,MAAc;IACzC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAA,SAAS,MAAM,CAAC,OAAO,SAAS,CAAC,CAAC;IAEpE,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CACrC,8BAA8B,CACf,CAAC;IAClB,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CACrC,8BAA8B,CACf,CAAC;IAClB,MAAM,QAAQ,GAAG,OAAO,CAAC,aAAa,CACpC,0BAA0B,CACV,CAAC;IAEnB,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;IAC3B,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;IAE3B,OAAO;QACL,OAAO;QACP,SAAS;QACT,SAAS;QACT,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,IAAI,SAAoB,CAAC;IACzB,IAAI,iBAAsC,CAAC;IAE3C,UAAU,CAAC,GAAG,EAAE;QACd,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,iBAAiB,EAAE,CAAC;YACtB,iBAAiB,CAAC,MAAM,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAE1C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,OAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,OAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC;QAEnC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC;QAEnC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC;QAEnC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAClD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QACrD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QACrD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC;QAEnC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAChD,yBAAyB,CAC1B,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;QAC1E,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC;QAEnC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAQ,CAAC,MAAM,CAClC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,EACpC,iBAAkB,CACP,CAAC;QAEd,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC;QAEnC,MAAM,CAAC,SAAS,CAAC,KAAK,GAAG,qBAAqB,CAAC;QAE/C,MAAM,KAAK,GAAG,MAAM,CAAC,OAAQ,CAAC,MAAM,CAClC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,EACpC,iBAAkB,CACP,CAAC;QAEd,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAkB,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,UAAW,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC;QAEnC,MAAM,CAAC,SAAS,CAAC,KAAK,GAAG,qBAAqB,CAAC;QAE/C,MAAM,KAAK,GAAG,MAAM,CAAC,OAAQ,CAAC,MAAM,CAClC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,EACpC,iBAAkB,CACP,CAAC;QAEd,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACxB,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACrE,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAE,CAAC;QAC1D,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAE5D,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC;QAEnC,MAAM,CAAC,SAAS,CAAC,KAAK,GAAG,IAAyB,CAAC;QAEnD,MAAM,KAAK,GAAG,MAAM,CAAC,OAAQ,CAAC,MAAM,CAClC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,EACpC,iBAAkB,CACP,CAAC;QAEd,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAkB,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,UAAW,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAEzC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACxB,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC;QAEnC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAE,CAAC;QAC1D,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC;QAEnC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAQ,CAAC,MAAM,CAClC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,EACpC,iBAAkB,CACP,CAAC;QAEd,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAE,CAAC;QAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9D,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAErC,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC;QAEnC,2BAA2B;QAC3B,MAAM,CAAC,QAAQ,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAClE,GAAG,IAAI;YACP,QAAQ,EAAE,KAAK,KAAK,CAAC;SACtB,CAAC,CAAC,CAAC;QAEJ,MAAM,KAAK,GAAG,MAAM,CAAC,OAAQ,CAAC,MAAM,CAClC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,EACpC,iBAAkB,CACP,CAAC;QAEd,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAW,CAAC;QACtC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6EAA6E,EAAE,KAAK,IAAI,EAAE;QAC3F,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAE,CAAC;QAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;QAE9D,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC;QAEnC,0BAA0B;QAC1B,MAAM,CAAC,QAAQ,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAClE,GAAG,IAAI;YACP,QAAQ,EAAE,KAAK,KAAK,CAAC;SACtB,CAAC,CAAC,CAAC;QAEJ,mBAAmB;QACnB,MAAM,CAAC,SAAS,CAAC,KAAK,GAAG,UAAU,CAAC;QAEpC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAQ,CAAC,MAAM,CAClC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,EACpC,iBAAkB,CACP,CAAC;QAEd,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAElC,0BAA0B;QAC1B,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAW,CAAC;QACtC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAE9C,kCAAkC;QAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAkB,CAAC;QAC3C,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3C,MAAM,CAAC,QAAQ,CAAC,UAAW,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAE,CAAC;QAC1D,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAE7D,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAC;QAC3C,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC;QAEnC,iCAAiC;QACjC,MAAM,CAAC,QAAQ,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAClE,GAAG,IAAI;YACP,QAAQ,EAAE,KAAK,KAAK,CAAC;SACtB,CAAC,CAAC,CAAC;QAEJ,MAAM,KAAK,GAAG,MAAM,CAAC,OAAQ,CAAC,MAAM,CAClC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,EACpC,iBAAkB,CACP,CAAC;QAEd,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAClC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACxB,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["/* eslint-disable @typescript-eslint/no-unused-expressions */\nimport { expect, fixture } from '@open-wc/testing';\nimport { html } from 'lit';\n\nimport { editDataSetWizard } from './dataset.js';\nimport { EditV2, Remove, SetAttributes } from '@openscd/oscd-api';\nimport { XMLEditor } from '@openscd/oscd-editor';\nimport { SclTextField } from '@openenergytools/scl-text-field';\nimport { SelectionList } from '@openenergytools/filterable-lists/dist/SelectionList.js';\nimport { Wizard } from '../foundation.js';\n\nif (!customElements.get('scl-text-field')) {\n customElements.define('scl-text-field', SclTextField);\n}\nif (!customElements.get('selection-list')) {\n customElements.define('selection-list', SelectionList);\n}\n\nconst xmlParser = new DOMParser();\nfunction createSclDoc(): XMLDocument {\n return xmlParser.parseFromString(\n `\n <SCL xmlns=\"http://www.iec.ch/61850/2003/SCL\">\n <IED name=\"IED1\">\n <AccessPoint name=\"AP1\">\n <Server>\n <LDevice inst=\"LD1\">\n <LN0 lnClass=\"LLN0\" inst=\"\" lnType=\"LLN0_Type\">\n <DataSet name=\"DS1\" desc=\"Data set 1\">\n <FCDA ldInst=\"LD1\" lnClass=\"LLN0\" doName=\"Beh\" daName=\"stVal\" fc=\"ST\" />\n <FCDA ldInst=\"LD1\" lnClass=\"LLN0\" doName=\"Beh\" daName=\"q\" fc=\"ST\" />\n <FCDA ldInst=\"LD1\" lnClass=\"MMXU\" lnInst=\"1\" doName=\"TotW\" fc=\"MX\" />\n </DataSet>\n <DataSet name=\"DS2\" />\n </LN0>\n </LDevice>\n </Server>\n </AccessPoint>\n </IED>\n </SCL>\n `,\n 'application/xml',\n );\n}\n\nasync function renderContent(wizard: Wizard) {\n const content = await fixture(html`<form>${wizard.content}</form>`);\n\n const nameField = content.querySelector(\n 'scl-text-field[label=\"name\"]',\n ) as SclTextField;\n const descField = content.querySelector(\n 'scl-text-field[label=\"desc\"]',\n ) as SclTextField;\n const fcdaList = content.querySelector(\n 'selection-list#fcda-list',\n ) as SelectionList;\n\n expect(nameField).to.exist;\n expect(descField).to.exist;\n\n return {\n content,\n nameField,\n descField,\n fcdaList,\n };\n}\n\ndescribe('DataSet edit wizard', () => {\n let xmlEditor: XMLEditor;\n let renderedContainer: Element | undefined;\n\n beforeEach(() => {\n xmlEditor = new XMLEditor();\n });\n\n afterEach(() => {\n if (renderedContainer) {\n renderedContainer.remove();\n }\n });\n\n it('returns a wizard with correct title and 3 content items', () => {\n const scl = createSclDoc();\n const element = scl.querySelector('DataSet[name=\"DS1\"]')!;\n const wizard = editDataSetWizard(element);\n\n expect(wizard.title).to.equal('Edit DataSet');\n expect(wizard.primary).to.exist;\n expect(wizard.primary!.icon).to.equal('edit');\n expect(wizard.primary!.label).to.equal('save');\n expect(wizard.content).to.have.lengthOf(3);\n });\n\n it('populates fields with current attribute values', async () => {\n const scl = createSclDoc();\n const element = scl.querySelector('DataSet[name=\"DS1\"]')!;\n const wizard = editDataSetWizard(element);\n const fields = await renderContent(wizard);\n renderedContainer = fields.content;\n\n expect(fields.nameField.value).to.equal('DS1');\n expect(fields.descField.value).to.equal('Data set 1');\n });\n\n it('renders name field as disabled', async () => {\n const scl = createSclDoc();\n const element = scl.querySelector('DataSet[name=\"DS1\"]')!;\n const wizard = editDataSetWizard(element);\n const fields = await renderContent(wizard);\n renderedContainer = fields.content;\n\n expect(fields.nameField.disabled).to.be.true;\n });\n\n it('renders the FCDA selection list', async () => {\n const scl = createSclDoc();\n const element = scl.querySelector('DataSet[name=\"DS1\"]')!;\n const wizard = editDataSetWizard(element);\n const fields = await renderContent(wizard);\n renderedContainer = fields.content;\n\n expect(fields.fcdaList).to.exist;\n expect(fields.fcdaList.items).to.have.lengthOf(3);\n expect(fields.fcdaList.items[0].selected).to.be.true;\n expect(fields.fcdaList.items[1].selected).to.be.true;\n expect(fields.fcdaList.items[2].selected).to.be.true;\n });\n\n it('renders FCDA labels with ldInst, lnClass, doName, daName, fc', async () => {\n const scl = createSclDoc();\n const element = scl.querySelector('DataSet[name=\"DS1\"]')!;\n const wizard = editDataSetWizard(element);\n const fields = await renderContent(wizard);\n renderedContainer = fields.content;\n\n expect(fields.fcdaList.items[0].headline).to.equal(\n 'LD1.LLN0.Beh.stVal.[ST]',\n );\n expect(fields.fcdaList.items[1].headline).to.equal('LD1.LLN0.Beh.q.[ST]');\n expect(fields.fcdaList.items[2].headline).to.equal('LD1.MMXU1.TotW.[MX]');\n });\n\n it('returns [] when no changes are made', async () => {\n const scl = createSclDoc();\n const element = scl.querySelector('DataSet[name=\"DS1\"]')!;\n const wizard = editDataSetWizard(element);\n const fields = await renderContent(wizard);\n renderedContainer = fields.content;\n\n const edits = wizard.primary!.action(\n [fields.nameField, fields.descField],\n renderedContainer!,\n ) as EditV2[];\n\n expect(edits).to.have.lengthOf(0);\n });\n\n it('returns SetAttributes with changed desc', async () => {\n const scl = createSclDoc();\n const element = scl.querySelector('DataSet[name=\"DS1\"]')!;\n const wizard = editDataSetWizard(element);\n const fields = await renderContent(wizard);\n renderedContainer = fields.content;\n\n fields.descField.value = 'Updated description';\n\n const edits = wizard.primary!.action(\n [fields.nameField, fields.descField],\n renderedContainer!,\n ) as EditV2[];\n\n expect(edits).to.have.lengthOf(1);\n const edit = edits[0] as SetAttributes;\n expect(edit.element).to.equal(element);\n expect(edit.attributes!.desc).to.equal('Updated description');\n });\n\n it('applies changed desc to the document', async () => {\n const scl = createSclDoc();\n const element = scl.querySelector('DataSet[name=\"DS1\"]')!;\n const wizard = editDataSetWizard(element);\n const fields = await renderContent(wizard);\n renderedContainer = fields.content;\n\n fields.descField.value = 'Updated description';\n\n const edits = wizard.primary!.action(\n [fields.nameField, fields.descField],\n renderedContainer!,\n ) as EditV2[];\n\n xmlEditor.commit(edits);\n expect(element.getAttribute('desc')).to.equal('Updated description');\n expect(element.getAttribute('name')).to.equal('DS1');\n });\n\n it('handles nullable desc — set to null removes attribute', async () => {\n const scl = createSclDoc();\n const element = scl.querySelector('DataSet[name=\"DS1\"]')!;\n expect(element.getAttribute('desc')).to.equal('Data set 1');\n\n const wizard = editDataSetWizard(element);\n const fields = await renderContent(wizard);\n renderedContainer = fields.content;\n\n fields.descField.value = null as unknown as string;\n\n const edits = wizard.primary!.action(\n [fields.nameField, fields.descField],\n renderedContainer!,\n ) as EditV2[];\n\n expect(edits).to.have.lengthOf(1);\n const edit = edits[0] as SetAttributes;\n expect(edit.attributes!.desc).to.be.null;\n\n xmlEditor.commit(edits);\n expect(element.getAttribute('desc')).to.be.null;\n });\n\n it('handles element with no FCDAs (DS2)', async () => {\n const scl = createSclDoc();\n const element = scl.querySelector('DataSet[name=\"DS2\"]')!;\n const wizard = editDataSetWizard(element);\n const fields = await renderContent(wizard);\n renderedContainer = fields.content;\n\n expect(fields.nameField.value).to.equal('DS2');\n expect(fields.descField.value).to.be.null;\n expect(fields.fcdaList).to.exist;\n expect(fields.fcdaList.items).to.have.lengthOf(0);\n });\n\n it('returns [] when no-attribute element is unchanged', async () => {\n const scl = createSclDoc();\n const element = scl.querySelector('DataSet[name=\"DS2\"]')!;\n const wizard = editDataSetWizard(element);\n const fields = await renderContent(wizard);\n renderedContainer = fields.content;\n\n const edits = wizard.primary!.action(\n [fields.nameField, fields.descField],\n renderedContainer!,\n ) as EditV2[];\n\n expect(edits).to.have.lengthOf(0);\n });\n\n it('returns Remove edits for deselected FCDAs', async () => {\n const scl = createSclDoc();\n const element = scl.querySelector('DataSet[name=\"DS1\"]')!;\n const allFcdas = Array.from(element.querySelectorAll('FCDA'));\n expect(allFcdas).to.have.lengthOf(3);\n\n const wizard = editDataSetWizard(element);\n const fields = await renderContent(wizard);\n renderedContainer = fields.content;\n\n // Deselect the second FCDA\n fields.fcdaList.items = fields.fcdaList.items.map((item, index) => ({\n ...item,\n selected: index !== 1,\n }));\n\n const edits = wizard.primary!.action(\n [fields.nameField, fields.descField],\n renderedContainer!,\n ) as EditV2[];\n\n expect(edits).to.have.lengthOf(1);\n const removeEdit = edits[0] as Remove;\n expect(removeEdit.node).to.equal(allFcdas[1]);\n });\n\n it('returns both Remove and SetAttributes when desc changed and FCDA deselected', async () => {\n const scl = createSclDoc();\n const element = scl.querySelector('DataSet[name=\"DS1\"]')!;\n const allFcdas = Array.from(element.querySelectorAll('FCDA'));\n\n const wizard = editDataSetWizard(element);\n const fields = await renderContent(wizard);\n renderedContainer = fields.content;\n\n // Deselect the first FCDA\n fields.fcdaList.items = fields.fcdaList.items.map((item, index) => ({\n ...item,\n selected: index !== 0,\n }));\n\n // Also change desc\n fields.descField.value = 'New desc';\n\n const edits = wizard.primary!.action(\n [fields.nameField, fields.descField],\n renderedContainer!,\n ) as EditV2[];\n\n expect(edits).to.have.lengthOf(2);\n\n // Remove edit comes first\n const removeEdit = edits[0] as Remove;\n expect(removeEdit.node).to.equal(allFcdas[0]);\n\n // SetAttributes edit comes second\n const setAttrs = edits[1] as SetAttributes;\n expect(setAttrs.element).to.equal(element);\n expect(setAttrs.attributes!.desc).to.equal('New desc');\n });\n\n it('applies FCDA removal to the document', async () => {\n const scl = createSclDoc();\n const element = scl.querySelector('DataSet[name=\"DS1\"]')!;\n expect(element.querySelectorAll('FCDA')).to.have.lengthOf(3);\n\n const wizard = editDataSetWizard(element);\n const fields = await renderContent(wizard);\n renderedContainer = fields.content;\n\n // Deselect first and third FCDAs\n fields.fcdaList.items = fields.fcdaList.items.map((item, index) => ({\n ...item,\n selected: index === 1,\n }));\n\n const edits = wizard.primary!.action(\n [fields.nameField, fields.descField],\n renderedContainer!,\n ) as EditV2[];\n\n expect(edits).to.have.lengthOf(2);\n xmlEditor.commit(edits);\n expect(element.querySelectorAll('FCDA')).to.have.lengthOf(1);\n });\n});\n"]}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
import { getValue, reservedNames, } from '../foundation.js';
|
|
3
|
+
import { maxLength, tGSEControlType, tSecurityEnable } from './patterns.js';
|
|
4
|
+
function render(options) {
|
|
5
|
+
return [
|
|
6
|
+
html `<scl-text-field
|
|
7
|
+
label="name"
|
|
8
|
+
.value=${options.name}
|
|
9
|
+
required
|
|
10
|
+
maxLength="${maxLength.cbName}"
|
|
11
|
+
.reservedValues=${options.reservedValues}
|
|
12
|
+
dialogInitialFocus
|
|
13
|
+
></scl-text-field>`,
|
|
14
|
+
html `<scl-text-field
|
|
15
|
+
label="desc"
|
|
16
|
+
.value=${options.desc}
|
|
17
|
+
nullable
|
|
18
|
+
></scl-text-field>`,
|
|
19
|
+
html `<scl-select
|
|
20
|
+
label="type"
|
|
21
|
+
.selectOptions=${tGSEControlType}
|
|
22
|
+
.value=${options.type}
|
|
23
|
+
nullable
|
|
24
|
+
></scl-select>`,
|
|
25
|
+
html `<scl-text-field
|
|
26
|
+
label="appID"
|
|
27
|
+
.value=${options.appID}
|
|
28
|
+
required
|
|
29
|
+
></scl-text-field>`,
|
|
30
|
+
html `<scl-checkbox
|
|
31
|
+
label="fixedOffs"
|
|
32
|
+
.value=${options.fixedOffs}
|
|
33
|
+
nullable
|
|
34
|
+
></scl-checkbox>`,
|
|
35
|
+
html `<scl-select
|
|
36
|
+
label="securityEnabled"
|
|
37
|
+
.selectOptions=${tSecurityEnable}
|
|
38
|
+
.value=${options.securityEnabled}
|
|
39
|
+
nullable
|
|
40
|
+
></scl-select>`,
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
function updateAction(element) {
|
|
44
|
+
return (inputs) => {
|
|
45
|
+
const name = getValue(inputs.find(i => i.label === 'name'));
|
|
46
|
+
const desc = getValue(inputs.find(i => i.label === 'desc'));
|
|
47
|
+
const type = getValue(inputs.find(i => i.label === 'type'));
|
|
48
|
+
const appID = getValue(inputs.find(i => i.label === 'appID'));
|
|
49
|
+
const fixedOffs = getValue(inputs.find(i => i.label === 'fixedOffs'));
|
|
50
|
+
const securityEnabled = getValue(inputs.find(i => i.label === 'securityEnabled'));
|
|
51
|
+
if (name === element.getAttribute('name') &&
|
|
52
|
+
desc === element.getAttribute('desc') &&
|
|
53
|
+
type === element.getAttribute('type') &&
|
|
54
|
+
appID === element.getAttribute('appID') &&
|
|
55
|
+
fixedOffs === element.getAttribute('fixedOffs') &&
|
|
56
|
+
securityEnabled === element.getAttribute('securityEnabled')) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
return [
|
|
60
|
+
{
|
|
61
|
+
element,
|
|
62
|
+
attributes: { name, desc, type, appID, fixedOffs, securityEnabled },
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function editGSEControlWizard(element) {
|
|
68
|
+
return {
|
|
69
|
+
title: 'Edit GSEControl',
|
|
70
|
+
primary: {
|
|
71
|
+
icon: 'edit',
|
|
72
|
+
label: 'save',
|
|
73
|
+
action: updateAction(element),
|
|
74
|
+
},
|
|
75
|
+
content: render({
|
|
76
|
+
name: element.getAttribute('name') ?? '',
|
|
77
|
+
reservedValues: reservedNames(element),
|
|
78
|
+
desc: element.getAttribute('desc'),
|
|
79
|
+
type: element.getAttribute('type'),
|
|
80
|
+
appID: element.getAttribute('appID') ?? '',
|
|
81
|
+
fixedOffs: element.getAttribute('fixedOffs'),
|
|
82
|
+
securityEnabled: element.getAttribute('securityEnabled'),
|
|
83
|
+
}),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=gsecontrol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gsecontrol.js","sourceRoot":"","sources":["../../wizards/gsecontrol.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, TemplateResult } from 'lit';\n\nimport { EditV2 } from '@openscd/oscd-api';\n\nimport {\n getValue,\n reservedNames,\n Wizard,\n WizardActor,\n WizardInputElement,\n} from '../foundation.js';\nimport { maxLength, tGSEControlType, tSecurityEnable } from './patterns.js';\n\ntype RenderOptions = {\n name: string;\n reservedValues: string[];\n desc: string | null;\n type: string | null;\n appID: string;\n fixedOffs: string | null;\n securityEnabled: string | null;\n};\n\nfunction render(options: RenderOptions): TemplateResult[] {\n return [\n html`<scl-text-field\n label=\"name\"\n .value=${options.name}\n required\n maxLength=\"${maxLength.cbName}\"\n .reservedValues=${options.reservedValues}\n dialogInitialFocus\n ></scl-text-field>`,\n html`<scl-text-field\n label=\"desc\"\n .value=${options.desc}\n nullable\n ></scl-text-field>`,\n html`<scl-select\n label=\"type\"\n .selectOptions=${tGSEControlType}\n .value=${options.type}\n nullable\n ></scl-select>`,\n html`<scl-text-field\n label=\"appID\"\n .value=${options.appID}\n required\n ></scl-text-field>`,\n html`<scl-checkbox\n label=\"fixedOffs\"\n .value=${options.fixedOffs}\n nullable\n ></scl-checkbox>`,\n html`<scl-select\n label=\"securityEnabled\"\n .selectOptions=${tSecurityEnable}\n .value=${options.securityEnabled}\n nullable\n ></scl-select>`,\n ];\n}\n\nfunction updateAction(element: Element): WizardActor {\n return (inputs: WizardInputElement[]): EditV2[] => {\n const name = getValue(inputs.find(i => i.label === 'name')!)!;\n const desc = getValue(inputs.find(i => i.label === 'desc')!);\n const type = getValue(inputs.find(i => i.label === 'type')!);\n const appID = getValue(inputs.find(i => i.label === 'appID')!)!;\n const fixedOffs = getValue(inputs.find(i => i.label === 'fixedOffs')!);\n const securityEnabled = getValue(\n inputs.find(i => i.label === 'securityEnabled')!,\n );\n\n if (\n name === element.getAttribute('name') &&\n desc === element.getAttribute('desc') &&\n type === element.getAttribute('type') &&\n appID === element.getAttribute('appID') &&\n fixedOffs === element.getAttribute('fixedOffs') &&\n securityEnabled === element.getAttribute('securityEnabled')\n ) {\n return [];\n }\n\n return [\n {\n element,\n attributes: { name, desc, type, appID, fixedOffs, securityEnabled },\n },\n ];\n };\n}\n\nexport function editGSEControlWizard(element: Element): Wizard {\n return {\n title: 'Edit GSEControl',\n primary: {\n icon: 'edit',\n label: 'save',\n action: updateAction(element),\n },\n content: render({\n name: element.getAttribute('name') ?? '',\n reservedValues: reservedNames(element),\n desc: element.getAttribute('desc'),\n type: element.getAttribute('type'),\n appID: element.getAttribute('appID') ?? '',\n fixedOffs: element.getAttribute('fixedOffs'),\n securityEnabled: element.getAttribute('securityEnabled'),\n }),\n };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
|
2
|
+
import { expect, fixture } from '@open-wc/testing';
|
|
3
|
+
import { html } from 'lit';
|
|
4
|
+
import { editGSEControlWizard } from './gsecontrol.js';
|
|
5
|
+
import { XMLEditor } from '@openscd/oscd-editor';
|
|
6
|
+
import { SclTextField } from '@openenergytools/scl-text-field';
|
|
7
|
+
import { SclSelect } from '@openenergytools/scl-select';
|
|
8
|
+
import { SclCheckbox } from '@openenergytools/scl-checkbox';
|
|
9
|
+
if (!customElements.get('scl-text-field')) {
|
|
10
|
+
customElements.define('scl-text-field', SclTextField);
|
|
11
|
+
}
|
|
12
|
+
if (!customElements.get('scl-select')) {
|
|
13
|
+
customElements.define('scl-select', SclSelect);
|
|
14
|
+
}
|
|
15
|
+
if (!customElements.get('scl-checkbox')) {
|
|
16
|
+
customElements.define('scl-checkbox', SclCheckbox);
|
|
17
|
+
}
|
|
18
|
+
const xmlParser = new DOMParser();
|
|
19
|
+
function createSclDoc() {
|
|
20
|
+
return xmlParser.parseFromString(`
|
|
21
|
+
<SCL xmlns="http://www.iec.ch/61850/2003/SCL">
|
|
22
|
+
<IED name="IED1">
|
|
23
|
+
<AccessPoint name="AP1">
|
|
24
|
+
<Server>
|
|
25
|
+
<LDevice inst="LD1">
|
|
26
|
+
<LN0 lnClass="LLN0" inst="" lnType="LLN0_Type">
|
|
27
|
+
<GSEControl name="GCB1" desc="GOOSE control 1" type="GOOSE" appID="APP1" fixedOffs="true" securityEnabled="None" datSet="ds1" confRev="1" />
|
|
28
|
+
<GSEControl name="GCB2" appID="APP2" />
|
|
29
|
+
</LN0>
|
|
30
|
+
</LDevice>
|
|
31
|
+
</Server>
|
|
32
|
+
</AccessPoint>
|
|
33
|
+
</IED>
|
|
34
|
+
</SCL>
|
|
35
|
+
`, 'application/xml');
|
|
36
|
+
}
|
|
37
|
+
async function renderContent(wizard) {
|
|
38
|
+
const content = await fixture(html `<form>${wizard.content}</form>`);
|
|
39
|
+
const nameField = content.querySelector('scl-text-field[label="name"]');
|
|
40
|
+
const descField = content.querySelector('scl-text-field[label="desc"]');
|
|
41
|
+
const typeField = content.querySelector('scl-select[label="type"]');
|
|
42
|
+
const appIDField = content.querySelector('scl-text-field[label="appID"]');
|
|
43
|
+
const fixedOffsField = content.querySelector('scl-checkbox[label="fixedOffs"]');
|
|
44
|
+
const securityEnabledField = content.querySelector('scl-select[label="securityEnabled"]');
|
|
45
|
+
expect(nameField).to.exist;
|
|
46
|
+
expect(descField).to.exist;
|
|
47
|
+
expect(typeField).to.exist;
|
|
48
|
+
expect(appIDField).to.exist;
|
|
49
|
+
expect(fixedOffsField).to.exist;
|
|
50
|
+
expect(securityEnabledField).to.exist;
|
|
51
|
+
return {
|
|
52
|
+
content,
|
|
53
|
+
nameField,
|
|
54
|
+
descField,
|
|
55
|
+
typeField,
|
|
56
|
+
appIDField,
|
|
57
|
+
fixedOffsField,
|
|
58
|
+
securityEnabledField,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
describe('GSEControl edit wizard', () => {
|
|
62
|
+
let xmlEditor;
|
|
63
|
+
let renderedContainer;
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
xmlEditor = new XMLEditor();
|
|
66
|
+
});
|
|
67
|
+
afterEach(() => {
|
|
68
|
+
if (renderedContainer) {
|
|
69
|
+
renderedContainer.remove();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
it('returns a wizard with correct title and all 6 fields', () => {
|
|
73
|
+
const scl = createSclDoc();
|
|
74
|
+
const element = scl.querySelector('GSEControl[name="GCB1"]');
|
|
75
|
+
const wizard = editGSEControlWizard(element);
|
|
76
|
+
expect(wizard.title).to.equal('Edit GSEControl');
|
|
77
|
+
expect(wizard.primary).to.exist;
|
|
78
|
+
expect(wizard.primary.icon).to.equal('edit');
|
|
79
|
+
expect(wizard.primary.label).to.equal('save');
|
|
80
|
+
expect(wizard.content).to.have.lengthOf(6);
|
|
81
|
+
});
|
|
82
|
+
it('populates fields with current attribute values', async () => {
|
|
83
|
+
const scl = createSclDoc();
|
|
84
|
+
const element = scl.querySelector('GSEControl[name="GCB1"]');
|
|
85
|
+
const wizard = editGSEControlWizard(element);
|
|
86
|
+
const fields = await renderContent(wizard);
|
|
87
|
+
renderedContainer = fields.content;
|
|
88
|
+
expect(fields.nameField.value).to.equal('GCB1');
|
|
89
|
+
expect(fields.descField.value).to.equal('GOOSE control 1');
|
|
90
|
+
expect(fields.typeField.value).to.equal('GOOSE');
|
|
91
|
+
expect(fields.appIDField.value).to.equal('APP1');
|
|
92
|
+
expect(fields.fixedOffsField.value).to.equal('true');
|
|
93
|
+
expect(fields.securityEnabledField.value).to.equal('None');
|
|
94
|
+
});
|
|
95
|
+
it('returns [] when no changes are made', async () => {
|
|
96
|
+
const scl = createSclDoc();
|
|
97
|
+
const element = scl.querySelector('GSEControl[name="GCB1"]');
|
|
98
|
+
const wizard = editGSEControlWizard(element);
|
|
99
|
+
const fields = await renderContent(wizard);
|
|
100
|
+
renderedContainer = fields.content;
|
|
101
|
+
const edits = wizard.primary.action([
|
|
102
|
+
fields.nameField,
|
|
103
|
+
fields.descField,
|
|
104
|
+
fields.typeField,
|
|
105
|
+
fields.appIDField,
|
|
106
|
+
fields.fixedOffsField,
|
|
107
|
+
fields.securityEnabledField,
|
|
108
|
+
], renderedContainer);
|
|
109
|
+
expect(edits).to.have.lengthOf(0);
|
|
110
|
+
});
|
|
111
|
+
it('returns SetAttributes with changed name', async () => {
|
|
112
|
+
const scl = createSclDoc();
|
|
113
|
+
const element = scl.querySelector('GSEControl[name="GCB1"]');
|
|
114
|
+
const wizard = editGSEControlWizard(element);
|
|
115
|
+
const fields = await renderContent(wizard);
|
|
116
|
+
renderedContainer = fields.content;
|
|
117
|
+
fields.nameField.value = 'GCB_New';
|
|
118
|
+
const edits = wizard.primary.action([
|
|
119
|
+
fields.nameField,
|
|
120
|
+
fields.descField,
|
|
121
|
+
fields.typeField,
|
|
122
|
+
fields.appIDField,
|
|
123
|
+
fields.fixedOffsField,
|
|
124
|
+
fields.securityEnabledField,
|
|
125
|
+
], renderedContainer);
|
|
126
|
+
expect(edits).to.have.lengthOf(1);
|
|
127
|
+
const edit = edits[0];
|
|
128
|
+
expect(edit.element).to.equal(element);
|
|
129
|
+
expect(edit.attributes.name).to.equal('GCB_New');
|
|
130
|
+
});
|
|
131
|
+
it('applies changed name to the document', async () => {
|
|
132
|
+
const scl = createSclDoc();
|
|
133
|
+
const element = scl.querySelector('GSEControl[name="GCB1"]');
|
|
134
|
+
const wizard = editGSEControlWizard(element);
|
|
135
|
+
const fields = await renderContent(wizard);
|
|
136
|
+
renderedContainer = fields.content;
|
|
137
|
+
fields.nameField.value = 'GCB_New';
|
|
138
|
+
const edits = wizard.primary.action([
|
|
139
|
+
fields.nameField,
|
|
140
|
+
fields.descField,
|
|
141
|
+
fields.typeField,
|
|
142
|
+
fields.appIDField,
|
|
143
|
+
fields.fixedOffsField,
|
|
144
|
+
fields.securityEnabledField,
|
|
145
|
+
], renderedContainer);
|
|
146
|
+
xmlEditor.commit(edits);
|
|
147
|
+
expect(element.getAttribute('name')).to.equal('GCB_New');
|
|
148
|
+
});
|
|
149
|
+
it('handles nullable desc correctly — set to null removes attribute', async () => {
|
|
150
|
+
const scl = createSclDoc();
|
|
151
|
+
const element = scl.querySelector('GSEControl[name="GCB1"]');
|
|
152
|
+
expect(element.getAttribute('desc')).to.equal('GOOSE control 1');
|
|
153
|
+
const wizard = editGSEControlWizard(element);
|
|
154
|
+
const fields = await renderContent(wizard);
|
|
155
|
+
renderedContainer = fields.content;
|
|
156
|
+
// Set desc to null (cleared)
|
|
157
|
+
fields.descField.value = null;
|
|
158
|
+
const edits = wizard.primary.action([
|
|
159
|
+
fields.nameField,
|
|
160
|
+
fields.descField,
|
|
161
|
+
fields.typeField,
|
|
162
|
+
fields.appIDField,
|
|
163
|
+
fields.fixedOffsField,
|
|
164
|
+
fields.securityEnabledField,
|
|
165
|
+
], renderedContainer);
|
|
166
|
+
expect(edits).to.have.lengthOf(1);
|
|
167
|
+
const edit = edits[0];
|
|
168
|
+
expect(edit.attributes.desc).to.be.null;
|
|
169
|
+
xmlEditor.commit(edits);
|
|
170
|
+
expect(element.getAttribute('desc')).to.be.null;
|
|
171
|
+
});
|
|
172
|
+
it('handles element with minimal attributes (GCB2)', async () => {
|
|
173
|
+
const scl = createSclDoc();
|
|
174
|
+
const element = scl.querySelector('GSEControl[name="GCB2"]');
|
|
175
|
+
const wizard = editGSEControlWizard(element);
|
|
176
|
+
const fields = await renderContent(wizard);
|
|
177
|
+
renderedContainer = fields.content;
|
|
178
|
+
expect(fields.nameField.value).to.equal('GCB2');
|
|
179
|
+
expect(fields.descField.value).to.be.null;
|
|
180
|
+
expect(fields.typeField.value).to.be.null;
|
|
181
|
+
expect(fields.appIDField.value).to.equal('APP2');
|
|
182
|
+
expect(fields.fixedOffsField.value).to.be.null;
|
|
183
|
+
expect(fields.securityEnabledField.value).to.be.null;
|
|
184
|
+
});
|
|
185
|
+
it('populates reservedValues with sibling GSEControl names', () => {
|
|
186
|
+
const scl = createSclDoc();
|
|
187
|
+
const element = scl.querySelector('GSEControl[name="GCB1"]');
|
|
188
|
+
const wizard = editGSEControlWizard(element);
|
|
189
|
+
// The first content item is the name field with reservedValues
|
|
190
|
+
const nameTemplate = wizard.content[0];
|
|
191
|
+
expect(nameTemplate).to.exist;
|
|
192
|
+
// Verify via the wizard that GCB2 is in reserved names (sibling)
|
|
193
|
+
// by trying to set name to GCB2 and checking the action still produces edits
|
|
194
|
+
// (validation is on the field component, not on the action)
|
|
195
|
+
});
|
|
196
|
+
it('returns SetAttributes with changed type', async () => {
|
|
197
|
+
const scl = createSclDoc();
|
|
198
|
+
const element = scl.querySelector('GSEControl[name="GCB1"]');
|
|
199
|
+
const wizard = editGSEControlWizard(element);
|
|
200
|
+
const fields = await renderContent(wizard);
|
|
201
|
+
renderedContainer = fields.content;
|
|
202
|
+
fields.typeField.value = 'GSSE';
|
|
203
|
+
const edits = wizard.primary.action([
|
|
204
|
+
fields.nameField,
|
|
205
|
+
fields.descField,
|
|
206
|
+
fields.typeField,
|
|
207
|
+
fields.appIDField,
|
|
208
|
+
fields.fixedOffsField,
|
|
209
|
+
fields.securityEnabledField,
|
|
210
|
+
], renderedContainer);
|
|
211
|
+
expect(edits).to.have.lengthOf(1);
|
|
212
|
+
const edit = edits[0];
|
|
213
|
+
expect(edit.attributes.type).to.equal('GSSE');
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
//# sourceMappingURL=gsecontrol.spec.js.map
|