diff --git a/src/Editing.ts b/src/Editing.ts index e685b8fe0d..b385429149 100644 --- a/src/Editing.ts +++ b/src/Editing.ts @@ -319,30 +319,32 @@ export function Editing(Base: TBase) { private checkUpdateValidity(update: Update): boolean { if (update.checkValidity !== undefined) return update.checkValidity(); - const invalidNaming = Array.from( - update.element.parentElement?.children ?? [] - ).some( - elm => - elm.tagName === update.element.tagName && - elm.getAttribute('name') === update.newAttributes['name'] - ); - - if (invalidNaming) { - this.dispatchEvent( - newLogEvent({ - kind: 'error', - title: get('editing.error.update', { - name: update.element.tagName, - }), - message: get('editing.error.nameClash', { - parent: update.element.parentElement!.tagName, - child: update.element.tagName, - name: update.newAttributes['name']!, - }), - }) + if (update.oldAttributes['name'] !== update.newAttributes['name']) { + const invalidNaming = Array.from( + update.element.parentElement?.children ?? [] + ).some( + elm => + elm.tagName === update.element.tagName && + elm.getAttribute('name') === update.newAttributes['name'] ); - return false; + if (invalidNaming) { + this.dispatchEvent( + newLogEvent({ + kind: 'error', + title: get('editing.error.update', { + name: update.element.tagName, + }), + message: get('editing.error.nameClash', { + parent: update.element.parentElement!.tagName, + child: update.element.tagName, + name: update.newAttributes['name']!, + }), + }) + ); + + return false; + } } const invalidId = diff --git a/src/editors/IED.ts b/src/editors/IED.ts index 4ada0788bc..e8d5ed5dee 100644 --- a/src/editors/IED.ts +++ b/src/editors/IED.ts @@ -16,13 +16,13 @@ import { Nsdoc } from '../foundation/nsdoc.js'; * We need a variable outside the plugin to save the selected IED, because the Plugin is created * more than once during working with the IED Editor, for instance when opening a Wizard to edit the IED. */ -let iedEditorSelectedIedName: string | undefined; +let iedEditorSelectedIed: Element | undefined; /* * We will also add an Event Listener when a new document is opened. We then want to reset the selection * so setting it to undefined will set the selected IED again on the first in the list. */ function onOpenDocResetSelectedIed() { - iedEditorSelectedIedName = undefined; + iedEditorSelectedIed = undefined; } addEventListener('open-doc', onOpenDocResetSelectedIed); @@ -45,14 +45,17 @@ export default class IedPlugin extends LitElement { @state() private set selectedIed(element: Element | undefined) { - iedEditorSelectedIedName = (element) ? getNameAttribute(element) : undefined; + iedEditorSelectedIed = element; } - private get selectedIed(): Element { - if (iedEditorSelectedIedName === undefined) { - iedEditorSelectedIedName = getNameAttribute(this.alphabeticOrderedIeds[0]); + private get selectedIed(): Element | undefined { + if (iedEditorSelectedIed === undefined) { + const iedList = this.alphabeticOrderedIeds; + if (iedList.length > 0) { + iedEditorSelectedIed = iedList[0]; + } } - return this.doc.querySelector(`:root > IED[name="${iedEditorSelectedIedName}"]`)!; + return iedEditorSelectedIed; } private onSelect(event: SingleSelectedEvent): void { @@ -63,11 +66,6 @@ export default class IedPlugin extends LitElement { render(): TemplateResult { const iedList = this.alphabeticOrderedIeds; if (iedList.length > 0) { - let selectedIedElement = this.selectedIed; - if (!selectedIedElement) { - // Fix: If the selected IED can't be found, because the name is changed, will select the first one again. - selectedIedElement = iedList[0]; - } return html `
html` ${getNameAttribute(ied)} ${ied.hasAttribute('desc') ? translate('iededitor.searchHelperDesc', { description: getDescriptionAttribute(ied)!, @@ -87,7 +85,7 @@ export default class IedPlugin extends LitElement { )}
`; diff --git a/src/editors/SingleLineDiagram.ts b/src/editors/SingleLineDiagram.ts index e1217e5bee..bea14474a5 100644 --- a/src/editors/SingleLineDiagram.ts +++ b/src/editors/SingleLineDiagram.ts @@ -58,13 +58,13 @@ import '@material/mwc-textfield'; * We need a variable outside the plugin to save the selected substation, because the Plugin is created * more than once during working with the SLD, for instance when opening a Wizard to edit equipment. */ -let sldEditorSelectedSubstationName: string | undefined; +let sldEditorSelectedSubstation: Element | undefined; /* * We will also add an Event Listener when a new document is opened. We then want to reset the selection * so setting it to undefined will set the selected Substation again on the first in the list. */ function onOpenDocResetSelectedSubstation() { - sldEditorSelectedSubstationName = undefined; + sldEditorSelectedSubstation = undefined; } addEventListener('open-doc', onOpenDocResetSelectedSubstation); @@ -90,19 +90,17 @@ export default class SingleLineDiagramPlugin extends LitElement { @state() private set selectedSubstation(element: Element | undefined) { - sldEditorSelectedSubstationName = (element) ? getNameAttribute(element) : undefined; + sldEditorSelectedSubstation = element; } private get selectedSubstation(): Element | undefined { - if (sldEditorSelectedSubstationName === undefined) { + if (sldEditorSelectedSubstation === undefined) { const substationList = this.substations; if (substationList.length > 0) { - sldEditorSelectedSubstationName = getNameAttribute(substationList[0]); + sldEditorSelectedSubstation = substationList[0]; } } - return (sldEditorSelectedSubstationName) - ? this.doc.querySelector(`:root > Substation[name="${sldEditorSelectedSubstationName}"]`) ?? undefined - : undefined; + return sldEditorSelectedSubstation; } /** diff --git a/src/translations/de.ts b/src/translations/de.ts index 361ab90797..762c5d0eeb 100644 --- a/src/translations/de.ts +++ b/src/translations/de.ts @@ -192,6 +192,7 @@ export const de: Translations = { }, action: { addvoltagelevel: 'Spannungsebene hinzufügen', + updatesubstation: 'Schaltanlage "{{name}}" bearbeitet', }, }, iededitor: { @@ -209,7 +210,7 @@ export const de: Translations = { }, }, action: { - updateied: 'IED "{{iedName}}" bearbeitet', + updateied: 'IED "{{name}}" bearbeitet', }, }, powertransformer: { diff --git a/src/translations/en.ts b/src/translations/en.ts index d0b9bf9f1d..2df7583ce4 100644 --- a/src/translations/en.ts +++ b/src/translations/en.ts @@ -189,6 +189,7 @@ export const en = { }, action: { addvoltagelevel: 'Add voltage level', + updatesubstation: 'Edited substation "{{name}}"', }, }, iededitor: { @@ -206,7 +207,7 @@ export const en = { }, }, action: { - updateied: 'Edited IED "{{iedName}}"', + updateied: 'Edited IED "{{name}}"', }, }, powertransformer: { diff --git a/src/wizards/foundation/actions.ts b/src/wizards/foundation/actions.ts index 0d18e40149..c3d2d6f594 100644 --- a/src/wizards/foundation/actions.ts +++ b/src/wizards/foundation/actions.ts @@ -1,10 +1,14 @@ import { cloneElement, + ComplexAction, + createUpdateAction, EditorAction, getValue, WizardActor, WizardInputElement, } from '../../foundation.js'; +import { get } from "lit-translate"; +import { updateReferences } from "./references.js"; export function updateNamingAction(element: Element): WizardActor { return (inputs: WizardInputElement[]): EditorAction[] => { @@ -14,11 +18,70 @@ export function updateNamingAction(element: Element): WizardActor { if ( name === element.getAttribute('name') && desc === element.getAttribute('desc') - ) + ) { return []; + } const newElement = cloneElement(element, { name, desc }); return [{ old: { element }, new: { element: newElement } }]; }; } + +export function updateNamingAttributeWithReferencesAction( + element: Element, + messageTitleKey: string +): WizardActor { + return (inputs: WizardInputElement[]): EditorAction[] => { + const newAttributes: Record = {}; + processNamingAttributes(newAttributes, element, inputs); + if (Object.keys(newAttributes).length == 0) { + return []; + } + addMissingAttributes(element, newAttributes) + + const name = getValue(inputs.find(i => i.label === 'name')!)!; + const complexAction: ComplexAction = { + actions: [], + title: get(messageTitleKey, {name}), + }; + complexAction.actions.push(createUpdateAction( + element, + newAttributes)); + complexAction.actions.push(...updateReferences( + element, + element.getAttribute('name'), + name)); + return complexAction.actions.length ? [complexAction] : []; + }; +} + +export function processNamingAttributes( + newAttributes: Record, + element: Element, + inputs: WizardInputElement[] +): void { + const name = getValue(inputs.find(i => i.label === 'name')!)!; + const desc = getValue(inputs.find(i => i.label === 'desc')!); + + if (name !== element.getAttribute('name')) { + newAttributes['name'] = name; + } + if (desc !== element.getAttribute('desc')) { + newAttributes['desc'] = desc; + } +} + +export function addMissingAttributes( + element: Element, + newAttributes: Record +): Record { + const newAttributeKeys = Object.keys(newAttributes); + Array.from(element.attributes) + .filter(attr => !newAttributeKeys.includes(attr.name)) + .forEach(attr => { + newAttributes[attr.name] = attr.value; + }); + + return newAttributes; +} diff --git a/src/wizards/foundation/references.ts b/src/wizards/foundation/references.ts index 6158cac6b3..86523659da 100644 --- a/src/wizards/foundation/references.ts +++ b/src/wizards/foundation/references.ts @@ -1,6 +1,6 @@ import {isPublic, SimpleAction} from "../../foundation.js"; -const referenceInfoTags = ['IED'] as const; +const referenceInfoTags = ['IED', 'Substation'] as const; type ReferencesInfoTag = typeof referenceInfoTags[number]; /* @@ -41,6 +41,11 @@ const referenceInfos: Record< }, { elementQuery: `SampledValueControl > IEDName`, attribute: null + }], + Substation: + [{ + elementQuery: `Terminal`, + attribute: 'substationName' }] } diff --git a/src/wizards/ied.ts b/src/wizards/ied.ts index 5aa23a3842..7fe15499b1 100644 --- a/src/wizards/ied.ts +++ b/src/wizards/ied.ts @@ -1,18 +1,10 @@ -import {html, TemplateResult} from 'lit-element'; -import {get, translate} from 'lit-translate'; +import { html, TemplateResult } from 'lit-element'; +import { get, translate } from 'lit-translate'; -import { - cloneElement, - ComplexAction, - EditorAction, - getValue, - isPublic, - Wizard, - WizardActor, - WizardInputElement, -} from '../foundation.js'; -import {patterns} from "./foundation/limits.js"; -import {updateReferences} from "./foundation/references.js"; +import '../wizard-textfield.js'; +import { isPublic, Wizard } from '../foundation.js'; +import { patterns } from "./foundation/limits.js"; +import { updateNamingAttributeWithReferencesAction } from "./foundation/actions.js"; const iedNamePattern = "[A-Za-z][0-9A-Za-z_]{0,2}|" + "[A-Za-z][0-9A-Za-z_]{4,63}|" + @@ -21,29 +13,6 @@ const iedNamePattern = "[A-Za-z][0-9A-Za-z_]{0,2}|" + "No[0-9A-Za-mo-z_][0-9A-Za-z_]|" + "Non[0-9A-Za-df-z_]"; -export function updateIED(element: Element): WizardActor { - return (inputs: WizardInputElement[]): EditorAction[] => { - const name = getValue(inputs.find(i => i.label === 'name')!)!; - const oldName = element.getAttribute('name'); - const desc = getValue(inputs.find(i => i.label === 'desc')!); - - if ( name === oldName && - desc === element.getAttribute('desc')) { - return []; - } - - const complexAction: ComplexAction = { - actions: [], - title: get('ied.action.updateied', {iedName: name}), - }; - - const newElement = cloneElement(element, { name, desc }); - complexAction.actions.push({ old: { element }, new: { element: newElement } }); - complexAction.actions.push(...updateReferences(element, oldName, name)); - return complexAction.actions.length ? [complexAction] : []; - }; -} - export function renderIEDWizard( name: string | null, desc: string | null, @@ -87,7 +56,7 @@ export function editIEDWizard(element: Element): Wizard { primary: { icon: 'edit', label: get('save'), - action: updateIED(element), + action: updateNamingAttributeWithReferencesAction(element, 'ied.action.updateied'), }, content: renderIEDWizard( element.getAttribute('name'), diff --git a/src/wizards/substation.ts b/src/wizards/substation.ts index 35911983bf..22faec59fb 100644 --- a/src/wizards/substation.ts +++ b/src/wizards/substation.ts @@ -14,8 +14,8 @@ import { WizardActor, WizardInputElement, } from '../foundation.js'; -import { updateNamingAction } from './foundation/actions.js'; import { guessVoltageLevel } from '../editors/substation/guess-wizard.js'; +import { updateNamingAttributeWithReferencesAction } from "./foundation/actions.js"; function render( name: string, @@ -97,7 +97,7 @@ export function substationEditWizard(element: Element): Wizard { primary: { icon: 'edit', label: get('save'), - action: updateNamingAction(element), + action: updateNamingAttributeWithReferencesAction(element, 'substation.action.updatesubstation'), }, content: render( element.getAttribute('name') ?? '', diff --git a/test/testfiles/wizards/substation.scd b/test/testfiles/wizards/substation.scd new file mode 100644 index 0000000000..82e3096a72 --- /dev/null +++ b/test/testfiles/wizards/substation.scd @@ -0,0 +1,328 @@ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + 380.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 110.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10.0 + + + + + + + + + + + + + + + + + + + + + + + 110.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/unit/wizards/__snapshots__/ied.test.snap.js b/test/unit/wizards/__snapshots__/ied.test.snap.js index 12d6ae42f9..bd871dae34 100644 --- a/test/unit/wizards/__snapshots__/ied.test.snap.js +++ b/test/unit/wizards/__snapshots__/ied.test.snap.js @@ -1,7 +1,7 @@ /* @web/test-runner snapshot v1 */ export const snapshots = {}; -snapshots["Wizards for SCL element IED looks like the latest snapshot"] = +snapshots["Wizards for SCL element IED edit existing IED looks like the latest snapshot"] = ` `; -/* end snapshot Wizards for SCL element IED looks like the latest snapshot */ +/* end snapshot Wizards for SCL element IED edit existing IED looks like the latest snapshot */ diff --git a/test/unit/wizards/__snapshots__/substation.test.snap.js b/test/unit/wizards/__snapshots__/substation.test.snap.js new file mode 100644 index 0000000000..2611701e84 --- /dev/null +++ b/test/unit/wizards/__snapshots__/substation.test.snap.js @@ -0,0 +1,85 @@ +/* @web/test-runner snapshot v1 */ +export const snapshots = {}; + +snapshots["Wizards for SCL element Substation edit existing Substation looks like the latest snapshot"] = +` +
+ + + + +
+ + + + +
+`; +/* end snapshot Wizards for SCL element Substation edit existing Substation looks like the latest snapshot */ + +snapshots["Wizards for SCL element Substation add new Substation looks like the latest snapshot"] = +` +
+ + + + +
+ + + + +
+`; +/* end snapshot Wizards for SCL element Substation add new Substation looks like the latest snapshot */ + diff --git a/test/unit/wizards/foundation.ts b/test/unit/wizards/foundation.ts index 4564b28de2..6f1dd4769b 100644 --- a/test/unit/wizards/foundation.ts +++ b/test/unit/wizards/foundation.ts @@ -1,13 +1,15 @@ import { expect } from '@open-wc/testing'; import { + Create, + isCreate, isReplace, - SimpleAction, + isUpdate, Replace, + SimpleAction, + Update, WizardActor, WizardInputElement, - Create, - isCreate, } from '../../../src/foundation.js'; import { WizardTextField } from '../../../src/wizard-textfield.js'; @@ -59,13 +61,13 @@ export function expectWizardNoUpdateAction( expect(updateActions).to.be.empty; } -export function expectUpdateAction( +export function expectReplaceAction( simpleAction: SimpleAction, tagName: string, attributeName: string, oldValue: string | null, newValue: string | null -) { +): void { expect(simpleAction).to.satisfy(isReplace); expect((simpleAction).old.element.tagName).to.be.equal(tagName); @@ -93,6 +95,33 @@ export function expectUpdateAction( } } +export function expectUpdateAction( + simpleAction: SimpleAction, + tagName: string, + attributeName: string, + oldValue: string | null, + newValue: string | null +): void { + expect(simpleAction).to.satisfy(isUpdate); + + expect((simpleAction).element.tagName).to.be.equal(tagName); + const oldAttributes = (simpleAction).oldAttributes; + if (oldValue === null) { + expect(Object.keys(oldAttributes)).to.not.contain(attributeName); + } else { + expect(Object.keys(oldAttributes)).to.contain(attributeName); + expect(Object.values(oldAttributes)).to.contain(oldValue); + } + + const newAttributes = (simpleAction).newAttributes; + if (newValue === null) { + expect(Object.keys(newAttributes)).to.not.contain(attributeName); + } else { + expect(Object.keys(newAttributes)).to.contain(attributeName); + expect(Object.values(newAttributes)).to.contain(newValue); + } +} + export function expectUpdateTextValue( action: Replace, parentTagName: string, diff --git a/test/unit/wizards/foundation/references.test.ts b/test/unit/wizards/foundation/references.test.ts index 2a2978773f..bf408b60c1 100644 --- a/test/unit/wizards/foundation/references.test.ts +++ b/test/unit/wizards/foundation/references.test.ts @@ -1,5 +1,5 @@ import { - expectUpdateAction, + expectReplaceAction, expectUpdateTextValue, fetchDoc, } from '../foundation.js'; @@ -23,35 +23,35 @@ describe('Update reference for ', () => { const updateActions = updateReferences(ied, oldName, newName); expect(updateActions.length).to.equal(9); - expectUpdateAction( + expectReplaceAction( updateActions[0], 'Association', 'iedName', oldName, newName ); - expectUpdateAction( + expectReplaceAction( updateActions[1], 'ClientLN', 'iedName', oldName, newName ); - expectUpdateAction( + expectReplaceAction( updateActions[3], 'ConnectedAP', 'iedName', oldName, newName ); - expectUpdateAction( + expectReplaceAction( updateActions[4], 'ExtRef', 'iedName', oldName, newName ); - expectUpdateAction( + expectReplaceAction( updateActions[8], 'KDC', 'iedName', @@ -68,7 +68,7 @@ describe('Update reference for ', () => { const updateActions = updateReferences(ied, oldName, newName); expect(updateActions.length).to.equal(8); - expectUpdateAction( + expectReplaceAction( updateActions[4], 'LNode', 'iedName', diff --git a/test/unit/wizards/ied.test.ts b/test/unit/wizards/ied.test.ts index f5a7f3ecfd..0f58281689 100644 --- a/test/unit/wizards/ied.test.ts +++ b/test/unit/wizards/ied.test.ts @@ -9,15 +9,17 @@ import { isSimple, WizardInputElement, } from '../../../src/foundation.js'; -import { editIEDWizard, updateIED } from '../../../src/wizards/ied.js'; +import { editIEDWizard } from '../../../src/wizards/ied.js'; import { + expectReplaceAction, expectUpdateAction, expectWizardNoUpdateAction, fetchDoc, newWizard, setWizardTextFieldValue, } from './foundation.js'; +import { updateNamingAttributeWithReferencesAction } from "../../../src/wizards/foundation/actions.js"; describe('Wizards for SCL element IED', () => { let doc: XMLDocument; @@ -25,69 +27,59 @@ describe('Wizards for SCL element IED', () => { let element: MockWizard; let inputs: WizardInputElement[]; - beforeEach(async () => { - doc = await fetchDoc('/test/testfiles/wizards/ied.scd'); - ied = doc.querySelector('IED[name="IED3"]')!; + describe('edit existing IED', () => { + beforeEach(async () => { + doc = await fetchDoc('/test/testfiles/wizards/ied.scd'); + ied = doc.querySelector('IED[name="IED3"]')!; - element = await fixture(html``); - const wizard = editIEDWizard(ied); - element.workflow.push(() => wizard); - await element.requestUpdate(); - inputs = Array.from(element.wizardUI.inputs); - }); + element = await fixture(html``); + const wizard = editIEDWizard(ied); + element.workflow.push(() => wizard); + await element.requestUpdate(); + inputs = Array.from(element.wizardUI.inputs); + }); - it('update name should be updated in document', async function () { - await setWizardTextFieldValue(inputs[0], 'OtherIED3'); + it('update name should be updated in document', async function () { + await setWizardTextFieldValue(inputs[0], 'OtherIED3'); - const complexAction = updateIED(ied)(inputs, newWizard()); - expect(complexAction.length).to.equal(1); - expect(complexAction[0]).to.not.satisfy(isSimple); + const complexAction = updateNamingAttributeWithReferencesAction(ied, 'ied.action.updateied')(inputs, newWizard()); + expect(complexAction.length).to.equal(1); + expect(complexAction[0]).to.not.satisfy(isSimple); - const simpleActions = (complexAction[0]).actions; - expect(simpleActions.length).to.equal(2); + const simpleActions = (complexAction[0]).actions; + expect(simpleActions.length).to.equal(2); - expectUpdateAction(simpleActions[0], 'IED', 'name', 'IED3', 'OtherIED3'); - expectUpdateAction( - simpleActions[1], - 'ConnectedAP', - 'iedName', - 'IED3', - 'OtherIED3' - ); - }); + expectUpdateAction(simpleActions[0], 'IED', 'name', 'IED3', 'OtherIED3'); + expectReplaceAction(simpleActions[1], 'ConnectedAP', 'iedName', 'IED3', 'OtherIED3'); + }); - it('update name should be unique in document', async function () { - await setWizardTextFieldValue(inputs[0], 'IED2'); - expect(inputs[0].checkValidity()).to.be.false; - }); + it('update name should be unique in document', async function () { + await setWizardTextFieldValue(inputs[0], 'IED2'); + expect(inputs[0].checkValidity()).to.be.false; + }); - it('update description should be updated in document', async function () { - await setWizardTextFieldValue( - inputs[1], - 'Some description' - ); - - const complexAction = updateIED(ied)(inputs, newWizard()); - expect(complexAction.length).to.equal(1); - expect(complexAction[0]).to.not.satisfy(isSimple); - - const simpleActions = (complexAction[0]).actions; - expect(simpleActions.length).to.equal(1); - - expectUpdateAction( - simpleActions[0], - 'IED', - 'desc', - null, - 'Some description' - ); - }); + it('update description should be updated in document', async function () { + await setWizardTextFieldValue( + inputs[1], + 'Some description' + ); - it('when no fields changed there will be no update action', async function () { - expectWizardNoUpdateAction(updateIED(ied), inputs); - }); + const complexAction = updateNamingAttributeWithReferencesAction(ied, 'ied.action.updateied')(inputs, newWizard()); + expect(complexAction.length).to.equal(1); + expect(complexAction[0]).to.not.satisfy(isSimple); + + const simpleActions = (complexAction[0]).actions; + expect(simpleActions.length).to.equal(1); + + expectUpdateAction(simpleActions[0], 'IED', 'desc', null, 'Some description'); + }); + + it('when no fields changed there will be no update action', async function () { + expectWizardNoUpdateAction(updateNamingAttributeWithReferencesAction(ied, 'ied.action.updateied'), inputs); + }); - it('looks like the latest snapshot', async () => { - await expect(element.wizardUI.dialog).dom.to.equalSnapshot(); + it('looks like the latest snapshot', async () => { + await expect(element.wizardUI.dialog).dom.to.equalSnapshot(); + }); }); }); diff --git a/test/unit/wizards/powertransformer.test.ts b/test/unit/wizards/powertransformer.test.ts index 8272fdead9..0f5de0bf5f 100644 --- a/test/unit/wizards/powertransformer.test.ts +++ b/test/unit/wizards/powertransformer.test.ts @@ -94,7 +94,7 @@ describe('Wizards for SCL element Power Transformer', () => { await setWizardTextFieldValue(inputs[0], 'NewTA1'); const createAC = executeWizardCreateAction( - createAction(powerTransformer), + createAction(parent), inputs ); expect(createAC.new.element).to.have.attribute('name', 'NewTA1'); diff --git a/test/unit/wizards/substation.test.ts b/test/unit/wizards/substation.test.ts new file mode 100644 index 0000000000..8e0bd99cec --- /dev/null +++ b/test/unit/wizards/substation.test.ts @@ -0,0 +1,122 @@ +import { expect, fixture, html } from '@open-wc/testing'; + +import '../../mock-wizard.js'; +import { MockWizard } from '../../mock-wizard.js'; + +import { WizardTextField } from '../../../src/wizard-textfield.js'; +import { + ComplexAction, + isSimple, Replace, + WizardInputElement, +} from '../../../src/foundation.js'; + +import { + executeWizardCreateAction, + expectReplaceAction, + expectUpdateAction, + expectWizardNoUpdateAction, + fetchDoc, + newWizard, + setWizardTextFieldValue, +} from './foundation.js'; +import { updateNamingAttributeWithReferencesAction } from "../../../src/wizards/foundation/actions.js"; +import { + createAction, + createSubstationWizard, + substationEditWizard +} from "../../../src/wizards/substation.js"; + +describe('Wizards for SCL element Substation', () => { + let doc: XMLDocument; + let substation: Element; + let element: MockWizard; + let inputs: WizardInputElement[]; + + describe('edit existing Substation', () => { + beforeEach(async () => { + doc = await fetchDoc('/test/testfiles/wizards/substation.scd'); + substation = doc.querySelector('Substation[name="Sub1"]')!; + + element = await fixture(html``); + const wizard = substationEditWizard(substation); + element.workflow.push(() => wizard); + await element.requestUpdate(); + inputs = Array.from(element.wizardUI.inputs); + }); + + it('update name should be updated in document', async function () { + await setWizardTextFieldValue(inputs[0], 'OtherSub1'); + + const complexAction = updateNamingAttributeWithReferencesAction( + substation, + 'substation.action.updatesubstation' + )(inputs, newWizard()); + expect(complexAction.length).to.equal(1); + expect(complexAction[0]).to.not.satisfy(isSimple); + + const simpleActions = (complexAction[0]).actions; + expect(simpleActions.length).to.equal(7); + + expectUpdateAction(simpleActions[0], 'Substation', 'name', 'Sub1', 'OtherSub1'); + expectReplaceAction(simpleActions[1], 'Terminal', 'substationName', 'Sub1', 'OtherSub1'); + }); + + it('update description should be updated in document', async function () { + await setWizardTextFieldValue( + inputs[1], + 'Some description' + ); + + const complexAction = updateNamingAttributeWithReferencesAction( + substation, + 'substation.action.updatesubstation' + )(inputs, newWizard()); + expect(complexAction.length).to.equal(1); + expect(complexAction[0]).to.not.satisfy(isSimple); + + const simpleActions = (complexAction[0]).actions; + expect(simpleActions.length).to.equal(1); + + expectUpdateAction(simpleActions[0], 'Substation', 'desc', 'Substation 1', 'Some description'); + }); + + it('when no fields changed there will be no update action', async function () { + expectWizardNoUpdateAction(updateNamingAttributeWithReferencesAction( + substation, 'substation.action.updatesubstation' + ), inputs); + }); + + it('looks like the latest snapshot', async () => { + await expect(element.wizardUI.dialog).dom.to.equalSnapshot(); + }); + }); + + describe('add new Substation', () => { + let parent: Element; + + beforeEach(async () => { + doc = await fetchDoc('/test/testfiles/wizards/substation.scd'); + parent = doc.querySelector('SCL')!; + + element = await fixture(html``); + const wizard = createSubstationWizard(parent); + element.workflow.push(() => wizard); + await element.requestUpdate(); + inputs = Array.from(element.wizardUI.inputs); + }); + + it('create new Substation', async function () { + await setWizardTextFieldValue(inputs[0], 'NewSub'); + + const createAC = executeWizardCreateAction( + createAction(parent), + inputs + ); + expect(createAC.new.element).to.have.attribute('name', 'NewSub'); + }); + + it('looks like the latest snapshot', async () => { + await expect(element.wizardUI.dialog).dom.to.equalSnapshot(); + }); + }); +});