diff --git a/src/Editing.ts b/src/Editing.ts index 060c99b090..7e26faaed7 100644 --- a/src/Editing.ts +++ b/src/Editing.ts @@ -6,6 +6,7 @@ import { Delete, EditorAction, EditorActionEvent, + getReference, isCreate, isDelete, isMove, @@ -17,6 +18,7 @@ import { newLogEvent, newValidateEvent, OpenDocEvent, + SCLTag, SimpleAction, Update, } from './foundation.js'; @@ -72,6 +74,12 @@ export function Editing(Base: TBase) { private onCreate(action: Create) { if (!this.checkCreateValidity(action)) return false; + if (action.new.reference === undefined) + action.new.reference = getReference( + action.new.parent, + action.new.element.tagName + ); + action.new.parent.insertBefore(action.new.element, action.new.reference); return true; } @@ -89,6 +97,9 @@ export function Editing(Base: TBase) { } private onDelete(action: Delete) { + if (!action.old.reference) + action.old.reference = action.old.element.nextSibling; + action.old.element.remove(); return true; } @@ -138,6 +149,15 @@ export function Editing(Base: TBase) { private onMove(action: Move) { if (!this.checkMoveValidity(action)) return false; + if (!action.old.reference) + action.old.reference = action.old.element.nextSibling; + + if (action.new.reference === undefined) + action.new.reference = getReference( + action.new.parent, + action.old.element.tagName + ); + action.new.parent.insertBefore(action.old.element, action.new.reference); return true; } diff --git a/src/editors/Communication.ts b/src/editors/Communication.ts index 9963e5aa05..edd0f173b0 100644 --- a/src/editors/Communication.ts +++ b/src/editors/Communication.ts @@ -5,7 +5,6 @@ import { newWizardEvent, newActionEvent, createElement, - getReference, } from '../foundation.js'; import { selectors, styles } from './communication/foundation.js'; @@ -25,7 +24,6 @@ export default class CommunicationPlugin extends LitElement { new: { parent: this.doc.documentElement, element: createElement(this.doc, 'Communication', {}), - reference: getReference(this.doc.documentElement, 'Communication'), }, }) ); diff --git a/src/editors/Templates.ts b/src/editors/Templates.ts index a01dbc3953..28a548f0ef 100644 --- a/src/editors/Templates.ts +++ b/src/editors/Templates.ts @@ -3,7 +3,6 @@ import { translate } from 'lit-translate'; import { createElement, - getReference, identity, newActionEvent, newWizardEvent, @@ -127,10 +126,6 @@ export default class TemplatesPlugin extends LitElement { new: { parent: this.doc.documentElement, element: createElement(this.doc, 'DataTypeTemplates', {}), - reference: getReference( - this.doc.documentElement, - 'DataTypeTemplates' - ), }, }) ); diff --git a/src/editors/communication/connectedap-editor.ts b/src/editors/communication/connectedap-editor.ts index 871e40778e..4fdd98eac8 100644 --- a/src/editors/communication/connectedap-editor.ts +++ b/src/editors/communication/connectedap-editor.ts @@ -24,7 +24,6 @@ import { getValue, createElement, ComplexAction, - getReference, } from '../../foundation.js'; import { @@ -114,7 +113,6 @@ function createConnectedApAction(parent: Element): WizardActor { iedName: value.iedName, apName: value.apName, }), - reference: getReference(parent, 'ConnectedAP'), }, } ); @@ -225,7 +223,6 @@ export function editConnectedApAction(parent: Element): WizardActor { new: { parent: parent, element: newAddress, - reference: getReference(parent, 'Address'), }, }); diff --git a/src/editors/communication/subnetwork-editor.ts b/src/editors/communication/subnetwork-editor.ts index 2ce689f56e..9d1efbe0ce 100644 --- a/src/editors/communication/subnetwork-editor.ts +++ b/src/editors/communication/subnetwork-editor.ts @@ -20,7 +20,6 @@ import { patterns, compareNames, createElement, - getReference, cloneElement, } from '../../foundation.js'; @@ -149,7 +148,6 @@ export function createSubNetworkAction(parent: Element): WizardActor { new: { parent, element, - reference: getReference(parent, 'SubNetwork'), }, }; diff --git a/src/editors/substation/guess-wizard.ts b/src/editors/substation/guess-wizard.ts index 2f14713e91..81456ad39d 100644 --- a/src/editors/substation/guess-wizard.ts +++ b/src/editors/substation/guess-wizard.ts @@ -8,7 +8,6 @@ import { compareNames, createElement, EditorAction, - getReference, Wizard, WizardActor, WizardInput, @@ -205,7 +204,6 @@ function guessBasedOnCSWI(doc: XMLDocument): WizardActor { new: { parent: substation, element: voltageLevel, - reference: getReference(substation, 'VoltageLevel'), }, }); diff --git a/src/editors/templates/datype-wizards.ts b/src/editors/templates/datype-wizards.ts index 8a54b5bcb2..e6796046ba 100644 --- a/src/editors/templates/datype-wizards.ts +++ b/src/editors/templates/datype-wizards.ts @@ -4,13 +4,11 @@ import { get, translate } from 'lit-translate'; import { Create, EditorAction, - getReference, getValue, identity, newActionEvent, newWizardEvent, patterns, - SCLTag, selector, Wizard, WizardActor, @@ -167,7 +165,6 @@ function addPredefinedDAType( new: { parent, element, - reference: getReference(parent, element.tagName), }, }); diff --git a/src/editors/templates/dotype-wizards.ts b/src/editors/templates/dotype-wizards.ts index 0ca23aea3a..d3d41f938c 100644 --- a/src/editors/templates/dotype-wizards.ts +++ b/src/editors/templates/dotype-wizards.ts @@ -6,13 +6,11 @@ import { Create, createElement, EditorAction, - getReference, getValue, identity, isPublic, newActionEvent, newWizardEvent, - SCLTag, selector, Wizard, WizardActor, @@ -74,7 +72,6 @@ function createSDoAction(parent: Element): WizardActor { new: { parent, element, - reference: getReference(parent, element.tagName), }, }); @@ -216,7 +213,6 @@ function addPredefinedDOType( new: { parent, element, - reference: getReference(parent, element.tagName), }, }); diff --git a/src/editors/templates/enumtype-wizard.ts b/src/editors/templates/enumtype-wizard.ts index 458dd71449..50f7da39f1 100644 --- a/src/editors/templates/enumtype-wizard.ts +++ b/src/editors/templates/enumtype-wizard.ts @@ -5,14 +5,12 @@ import { cloneElement, createElement, EditorAction, - getReference, getValue, identity, isPublic, newActionEvent, newWizardEvent, patterns, - SCLTag, selector, Wizard, WizardActor, @@ -57,7 +55,6 @@ function createEnumValAction(parent: Element): WizardActor { new: { parent, element, - reference: getReference(parent, 'EnumVal'), }, }; @@ -195,7 +192,6 @@ function createAction(parent: Element, templates: XMLDocument): WizardActor { new: { parent, element, - reference: getReference(parent, element.tagName), }, }; diff --git a/src/editors/templates/foundation.ts b/src/editors/templates/foundation.ts index 9f8f7fb5a7..4030d999e5 100644 --- a/src/editors/templates/foundation.ts +++ b/src/editors/templates/foundation.ts @@ -5,10 +5,8 @@ import { cloneElement, Create, EditorAction, - getReference, getValue, isPublic, - SCLTag, WizardActor, WizardInput, } from '../../foundation.js'; @@ -98,7 +96,6 @@ export function addReferencedDataTypes( new: { parent, element: adjacent.cloneNode(true), - reference: getReference(parent, adjacent.tagName), }, }); }); diff --git a/src/editors/templates/lnodetype-wizard.ts b/src/editors/templates/lnodetype-wizard.ts index 4c9c835355..a1c33292e9 100644 --- a/src/editors/templates/lnodetype-wizard.ts +++ b/src/editors/templates/lnodetype-wizard.ts @@ -7,14 +7,12 @@ import { createElement, EditorAction, getChildElementsByTagName, - getReference, getValue, identity, isPublic, newActionEvent, newWizardEvent, patterns, - SCLTag, selector, Wizard, WizardActor, @@ -97,7 +95,6 @@ function createDoAction(parent: Element): WizardActor { new: { parent, element, - reference: getReference(parent, element.tagName), }, }); @@ -271,7 +268,6 @@ function createNewLNodeType(parent: Element, element: Element): WizardActor { new: { parent: element, element: DO, - reference: getReference(element, DO.tagName), }, }); }); @@ -280,7 +276,6 @@ function createNewLNodeType(parent: Element, element: Element): WizardActor { new: { parent, element, - reference: getReference(parent, element.tagName), }, }); @@ -358,7 +353,6 @@ function addPredefinedLNodeType( new: { parent, element: newLNodeType, - reference: getReference(parent, 'LNodeType'), }, }); diff --git a/src/foundation.ts b/src/foundation.ts index c937077a7f..45f461569d 100644 --- a/src/foundation.ts +++ b/src/foundation.ts @@ -19,20 +19,20 @@ export type ComplexAction = { export type EditorAction = SimpleAction | ComplexAction; /** Inserts `new.element` to `new.parent` before `new.reference`. */ export interface Create { - new: { parent: Element; element: Element; reference: Node | null }; + new: { parent: Element; element: Element; reference?: Node | null }; derived?: boolean; checkValidity?: () => boolean; } /** Removes `old.element` from `old.parent` before `old.reference`. */ export interface Delete { - old: { parent: Element; element: Element; reference: Node | null }; + old: { parent: Element; element: Element; reference?: Node | null }; derived?: boolean; checkValidity?: () => boolean; } /** Reparents of `old.element` to `new.parent` before `new.reference`. */ export interface Move { - old: { parent: Element; element: Element; reference: Node | null }; - new: { parent: Element; reference: Node | null }; + old: { parent: Element; element: Element; reference?: Node | null }; + new: { parent: Element; reference?: Node | null }; derived?: boolean; checkValidity?: () => boolean; } @@ -48,15 +48,13 @@ export function isCreate(action: EditorAction): action is Create { return ( (action as Update).old === undefined && (action as Create).new?.parent !== undefined && - (action as Create).new?.element !== undefined && - (action as Create).new?.reference !== undefined + (action as Create).new?.element !== undefined ); } export function isDelete(action: EditorAction): action is Delete { return ( (action as Delete).old?.parent !== undefined && (action as Delete).old?.element !== undefined && - (action as Delete).old?.reference !== undefined && (action as Update).new === undefined ); } @@ -64,10 +62,8 @@ export function isMove(action: EditorAction): action is Move { return ( (action as Move).old?.parent !== undefined && (action as Move).old?.element !== undefined && - (action as Move).old?.reference !== undefined && (action as Move).new?.parent !== undefined && - (action as Update).new?.element == undefined && - (action as Move).new?.reference !== undefined + (action as Update).new?.element == undefined ); } export function isUpdate(action: EditorAction): action is Update { diff --git a/src/menu/ImportIEDs.ts b/src/menu/ImportIEDs.ts index fce11f47bb..5d89dff6e9 100644 --- a/src/menu/ImportIEDs.ts +++ b/src/menu/ImportIEDs.ts @@ -5,7 +5,6 @@ import { get } from 'lit-translate'; import { createElement, EditorAction, - getReference, identity, newActionEvent, newLogEvent, @@ -93,7 +92,6 @@ function addCommunicationElements( new: { parent: doc.querySelector(':root')!, element: communication, - reference: getReference(doc.querySelector(':root')!, 'Communication'), }, }); @@ -125,7 +123,6 @@ function addCommunicationElements( new: { parent: communication, element: subNetwork, - reference: getReference(communication, 'SubNetwork'), }, }); createdSubNetworks.push(subNetwork); @@ -135,7 +132,6 @@ function addCommunicationElements( new: { parent: subNetwork, element, - reference: getReference(subNetwork, 'ConnectedAP'), }, }); }); @@ -206,10 +202,6 @@ function addEnumType( new: { parent: doc.querySelector(':root > DataTypeTemplates')!, element: enumType, - reference: getReference( - doc.querySelector(':root > DataTypeTemplates')!, - 'EnumType' - ), }, }; } @@ -245,10 +237,6 @@ function addDAType( new: { parent: doc.querySelector(':root > DataTypeTemplates')!, element: daType, - reference: getReference( - doc.querySelector(':root > DataTypeTemplates')!, - 'DAType' - ), }, }; } @@ -284,10 +272,6 @@ function addDOType( new: { parent: doc.querySelector(':root > DataTypeTemplates')!, element: doType, - reference: getReference( - doc.querySelector(':root > DataTypeTemplates')!, - 'DOType' - ), }, }; } @@ -324,10 +308,6 @@ function addLNodeType( new: { parent: doc.querySelector(':root > DataTypeTemplates')!, element: lNodeType, - reference: getReference( - doc.querySelector('DataTypeTemplates')!, - 'LNodeType' - ), }, }; } @@ -398,7 +378,6 @@ export async function importIED( new: { parent: doc!.querySelector(':root')!, element: ied, - reference: getReference(doc!.querySelector(':root')!, 'IED'), }, }); @@ -484,7 +463,6 @@ export default class ImportingIedPlugin extends LitElement { new: { parent: doc.documentElement, element, - reference: getReference(doc.documentElement, 'DataTypeTemplates'), }, }) ); diff --git a/src/menu/SubscriberInfo.ts b/src/menu/SubscriberInfo.ts index 5806087f46..883c6653e6 100644 --- a/src/menu/SubscriberInfo.ts +++ b/src/menu/SubscriberInfo.ts @@ -2,7 +2,6 @@ import { LitElement } from 'lit-element'; import { get } from 'lit-translate'; import { createElement, - getReference, getVersion, newActionEvent, SimpleAction, @@ -139,7 +138,6 @@ export function createMissingIEDNameSubscriberInfo( new: { parent: controlBlock, element: iedName!, - reference: getReference(controlBlock, 'IEDName'), }, }); }); diff --git a/src/wizards/address.ts b/src/wizards/address.ts index f7e788c387..424ee2625f 100644 --- a/src/wizards/address.ts +++ b/src/wizards/address.ts @@ -6,7 +6,6 @@ import { Create, createElement, Delete, - getReference, getValue, WizardInput, } from '../foundation.js'; @@ -108,7 +107,6 @@ export function updateAddress( new: { parent: parent, element: newAddress, - reference: getReference(parent, 'Address'), }, }); diff --git a/src/wizards/bay.ts b/src/wizards/bay.ts index 65ba72d8c3..832281437d 100644 --- a/src/wizards/bay.ts +++ b/src/wizards/bay.ts @@ -4,7 +4,6 @@ import { get, translate } from 'lit-translate'; import { createElement, EditorAction, - getReference, getValue, Wizard, WizardActor, @@ -44,7 +43,6 @@ export function createAction(parent: Element): WizardActor { new: { parent, element, - reference: getReference(parent, 'Bay'), }, }; diff --git a/src/wizards/bda.ts b/src/wizards/bda.ts index cf28c54fe0..abdc459e0b 100644 --- a/src/wizards/bda.ts +++ b/src/wizards/bda.ts @@ -5,12 +5,10 @@ import { cloneElement, createElement, EditorAction, - getReference, getValue, isPublic, newActionEvent, newWizardEvent, - SCLTag, Wizard, WizardActor, WizardInput, @@ -186,7 +184,6 @@ export function createBDaAction(parent: Element): WizardActor { new: { parent, element, - reference: getReference(parent, element.tagName), }, }, ]; diff --git a/src/wizards/clientln.ts b/src/wizards/clientln.ts index af4629f01c..a6889a0ad8 100644 --- a/src/wizards/clientln.ts +++ b/src/wizards/clientln.ts @@ -3,9 +3,7 @@ import { get } from 'lit-translate'; import { createElement, - getReference, identity, - newWizardEvent, pathParts, selector, Wizard, @@ -16,7 +14,6 @@ import { import { List } from '@material/mwc-list'; import { ListItemBase } from '@material/mwc-list/mwc-list-item-base'; -import { SingleSelectedEvent } from '@material/mwc-list/mwc-list-foundation'; import { openCommunicationMappingWizard } from './commmap-wizards.js'; import { clientIcon } from '../icons.js'; @@ -159,10 +156,6 @@ function addClientLnAction(doc: XMLDocument): WizardActor { new: { parent: cb.querySelector('RptEnabled')!, element, - reference: getReference( - cb.querySelector('RptEnabled')!, - 'ClientLN' - ), }, }); } diff --git a/src/wizards/conductingequipment.ts b/src/wizards/conductingequipment.ts index 5087229442..40c8820ab9 100644 --- a/src/wizards/conductingequipment.ts +++ b/src/wizards/conductingequipment.ts @@ -4,7 +4,6 @@ import { get, translate } from 'lit-translate'; import { createElement, EditorAction, - getReference, getValue, isPublic, Wizard, @@ -135,7 +134,6 @@ export function createAction(parent: Element): WizardActor { new: { parent, element, - reference: getReference(parent, 'ConductingEquipment'), }, }; diff --git a/src/wizards/da.ts b/src/wizards/da.ts index 4348b45744..3823057c01 100644 --- a/src/wizards/da.ts +++ b/src/wizards/da.ts @@ -5,12 +5,10 @@ import { cloneElement, createElement, EditorAction, - getReference, getValue, isPublic, newActionEvent, newWizardEvent, - SCLTag, Wizard, WizardActor, WizardInput, @@ -267,7 +265,6 @@ export function createDaAction(parent: Element): WizardActor { new: { parent, element, - reference: getReference(parent, element.tagName), }, }); diff --git a/src/wizards/lnode.ts b/src/wizards/lnode.ts index 1421284684..974ca5ba78 100644 --- a/src/wizards/lnode.ts +++ b/src/wizards/lnode.ts @@ -5,7 +5,6 @@ import { createElement, EditorAction, getChildElementsByTagName, - getReference, identity, isPublic, referencePath, @@ -91,7 +90,6 @@ function createAction(parent: Element, anyln: Element): EditorAction { new: { parent, element, - reference: getReference(parent, 'LNode'), }, }; } diff --git a/src/wizards/substation.ts b/src/wizards/substation.ts index f3d76d5ef1..d34d089fc6 100644 --- a/src/wizards/substation.ts +++ b/src/wizards/substation.ts @@ -4,7 +4,6 @@ import { get, translate } from 'lit-translate'; import { createElement, EditorAction, - getReference, getValue, newWizardEvent, Wizard, @@ -58,7 +57,6 @@ export function createAction(parent: Element): WizardActor { new: { parent, element, - reference: getReference(parent, 'Substation'), }, }; diff --git a/src/wizards/voltagelevel.ts b/src/wizards/voltagelevel.ts index 38beaf93a8..063817c338 100644 --- a/src/wizards/voltagelevel.ts +++ b/src/wizards/voltagelevel.ts @@ -6,7 +6,6 @@ import { createElement, EditorAction, getMultiplier, - getReference, getValue, patterns, Wizard, @@ -111,7 +110,6 @@ export function createAction(parent: Element): WizardActor { new: { parent, element, - reference: getReference(parent, 'VoltageLevel'), }, }, ]; diff --git a/test/integration/Editing.test.ts b/test/integration/Editing.test.ts new file mode 100644 index 0000000000..435bf5f4c1 --- /dev/null +++ b/test/integration/Editing.test.ts @@ -0,0 +1,89 @@ +import { expect, fixture, html } from '@open-wc/testing'; + +import { newActionEvent } from '../../src/foundation.js'; +import { MockEditorLogger } from '../mock-editor-logger.js'; + +import '../mock-editor-logger.js'; + +describe('Editing-Logging integration', () => { + let elm: MockEditorLogger; + let parent: Element; + let element: Element; + + beforeEach(async () => { + const doc = await fetch('/base/test/testfiles/Editing.scd') + .then(response => response.text()) + .then(str => new DOMParser().parseFromString(str, 'application/xml')); + elm = ( + await fixture(html``) + ); + + parent = elm.doc!.querySelector('VoltageLevel[name="E1"]')!; + element = parent.querySelector('Bay[name="Q01"]')!; + }); + + it('add valid reference onCreate when reference is missing', () => { + const newElement = elm.doc!.createElement('Bay'); + newElement?.setAttribute('name', 'Q03'); + + elm.dispatchEvent( + newActionEvent({ + new: { + parent, + element: newElement, + }, + }) + ); + expect(parent.querySelector('Bay[name="Q03"]')).to.not.be.null; + elm.undo(); + expect(parent.querySelector('Bay[name="Q03"]')).to.be.null; + elm.redo(); + expect(parent.querySelector('Bay[name="Q03"]')).to.not.be.null; + expect( + parent.querySelector('Bay[name="Q03"]')?.nextElementSibling + ).to.equal(parent.querySelector('Bay[name="Q01"]')); + }); + + it('add valid reference onDelete when reference is missing', () => { + elm.dispatchEvent( + newActionEvent({ + old: { + parent, + element, + }, + }) + ); + expect(parent.querySelector('Bay[name="Q01"]')).to.be.null; + elm.undo(); + expect(parent.querySelector('Bay[name="Q01"]')).to.not.be.null; + expect( + parent.querySelector('Bay[name="Q01"]')?.nextElementSibling + ).to.equal(parent.querySelector('Bay[name="Q02"]')); + }); + + it('add valid reference onMove when reference is missing', () => { + elm.dispatchEvent( + newActionEvent({ + old: { + parent, + element, + }, + new: { + parent: elm.doc!.querySelector('VoltageLevel[name="J1"]')!, + }, + }) + ); + expect(parent.querySelector('Bay[name="Q01"]')).to.be.null; + expect(elm.doc!.querySelector('VoltageLevel[name="J1"] > Bay[name="Q01"]')) + .to.not.be.null; + elm.undo(); + expect( + parent.querySelector('Bay[name="Q01"]')?.nextElementSibling + ).to.equal(parent.querySelector('Bay[name="Q02"]')); + elm.redo(); + expect( + elm.doc!.querySelector('VoltageLevel[name="J1"] > Bay[name="Q01"]') + ?.nextElementSibling + ).to.equal(elm.doc!.querySelector('VoltageLevel[name="J1"] > Function')); + }); +}); diff --git a/test/mock-editor-logger.ts b/test/mock-editor-logger.ts new file mode 100644 index 0000000000..fe99e943ac --- /dev/null +++ b/test/mock-editor-logger.ts @@ -0,0 +1,7 @@ +import { LitElement, customElement } from 'lit-element'; + +import { Editing } from '../src/Editing.js'; +import { Logging } from '../src/Logging.js'; + +@customElement('mock-editor-logger') +export class MockEditorLogger extends Editing(Logging(LitElement)) {} diff --git a/test/testfiles/Editing.scd b/test/testfiles/Editing.scd new file mode 100644 index 0000000000..b68b2ce590 --- /dev/null +++ b/test/testfiles/Editing.scd @@ -0,0 +1,41 @@ + + +
+ TrainingIEC61850 + + +
+ + + 110 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/unit/Editing.test.ts b/test/unit/Editing.test.ts index 7bb44df33e..56c722a2b3 100644 --- a/test/unit/Editing.test.ts +++ b/test/unit/Editing.test.ts @@ -1,8 +1,8 @@ import { html, fixture, expect } from '@open-wc/testing'; import { EditingElement } from '../../src/Editing.js'; -import { mockSCD } from './mock-document.js'; import { newActionEvent } from '../../src/foundation.js'; + import './mock-editor.js'; describe('EditingElement', () => { @@ -12,13 +12,15 @@ describe('EditingElement', () => { let reference: Node | null; beforeEach(async () => { - const doc = mockSCD(); + const doc = await fetch('/base/test/testfiles/Editing.scd') + .then(response => response.text()) + .then(str => new DOMParser().parseFromString(str, 'application/xml')); elm = ( await fixture(html``) ); - parent = elm.doc!.querySelector('parent1')!; - element = parent.querySelector('child1')!; + parent = elm.doc!.querySelector('VoltageLevel[name="E1"]')!; + element = parent.querySelector('Bay[name="Q01"]')!; reference = element.nextSibling; }); @@ -27,12 +29,60 @@ describe('EditingElement', () => { newActionEvent({ new: { parent, - element: elm.doc!.createElement('child3'), + element: elm.doc!.createElement('newBay'), + reference: null, + }, + }) + ); + expect(elm.doc!.querySelector('newBay')).to.not.be.null; + }); + + it('triggers getReference with missing reference on Create Action', () => { + elm.dispatchEvent( + newActionEvent({ + new: { + parent, + element: elm.doc!.createElement('Bay'), + }, + }) + ); + expect(parent.querySelector('Bay')?.nextElementSibling).to.equal( + parent.querySelector('Bay[name="Q01"]') + ); + }); + + it('ignores getReference with existing reference on Create Action', () => { + const newElement = elm.doc!.createElement('Bay'); + newElement?.setAttribute('name', 'Q03'); + + elm.dispatchEvent( + newActionEvent({ + new: { + parent, + element: newElement, + reference: parent.querySelector('Bay[name="Q02"]'), + }, + }) + ); + expect( + parent.querySelector('Bay[name="Q03"]')?.nextElementSibling + ).to.equal(parent.querySelector('Bay[name="Q02"]')); + }); + + it('does not creates an element on name attribute conflict', () => { + const newElement = elm.doc!.createElement('Bay'); + newElement?.setAttribute('name', 'Q01'); + + elm.dispatchEvent( + newActionEvent({ + new: { + parent, + element: newElement, reference: null, }, }) ); - expect(elm.doc!.querySelector('child3')).to.not.be.null; + expect(parent.querySelectorAll('Bay[name="Q01"]').length).to.be.equal(1); }); it('deletes an element on receiving a Delete action', () => { @@ -45,7 +95,8 @@ describe('EditingElement', () => { }, }) ); - expect(elm.doc!.querySelector('parent1 > child1')).to.be.null; + expect(elm.doc!.querySelector('VoltageLevel[name="E1"] > Bay[name="Q01"]')) + .to.be.null; }); it('updates an element on receiving an Update action', () => { @@ -55,17 +106,37 @@ describe('EditingElement', () => { element, }, new: { - element: elm.doc!.createElement('child3'), + element: elm.doc!.createElement('newBay'), }, }) ); - expect(parent.querySelector('child1')).to.be.null; - expect(parent.querySelector('child3')).to.not.be.null; - expect(parent.querySelector('child3')?.nextElementSibling).to.equal( - parent.querySelector('child2') + expect(parent.querySelector('Bay[name="Q01"]')).to.be.null; + expect(parent.querySelector('newBay')).to.not.be.null; + expect(parent.querySelector('newBay')?.nextElementSibling).to.equal( + parent.querySelector('Bay[name="Q02"]') ); }); + it('does not update an element with name conflict', () => { + const newElement = elm.doc!.createElement('Bay'); + newElement?.setAttribute('name', 'Q02'); + + elm.dispatchEvent( + newActionEvent({ + old: { + element, + }, + new: { + element: newElement, + }, + }) + ); + expect(parent.querySelector('Bay[name="Q01"]')).to.not.null; + expect( + parent.querySelector('Bay[name="Q01"]')?.nextElementSibling + ).to.equal(parent.querySelector('Bay[name="Q02"]')); + }); + it('moves an element on receiving a Move action', () => { elm.dispatchEvent( newActionEvent({ @@ -75,17 +146,63 @@ describe('EditingElement', () => { reference, }, new: { - parent: elm.doc!.querySelector('parent2')!, + parent: elm.doc!.querySelector('VoltageLevel[name="J1"]')!, + reference: null, + }, + }) + ); + expect(parent.querySelector('Bay[name="Q01"]')).to.be.null; + expect(elm.doc!.querySelector('VoltageLevel[name="J1"] > Bay[name="Q01"]')) + .to.not.be.null; + }); + + it('triggers getReference with missing reference on Move action', () => { + elm.dispatchEvent( + newActionEvent({ + old: { + parent, + element, + reference, + }, + new: { + parent: elm.doc!.querySelector('VoltageLevel[name="J1"]')!, + }, + }) + ); + expect(parent.querySelector('Bay[name="Q01"]')).to.be.null; + expect(elm.doc!.querySelector('VoltageLevel[name="J1"] > Bay[name="Q01"]')) + .to.not.be.null; + expect( + elm.doc!.querySelector('VoltageLevel[name="J1"] > Bay[name="Q01"]') + ?.nextElementSibling + ).to.equal(elm.doc!.querySelector('VoltageLevel[name="J1"] > Function')); + }); + + it('does not move an element with name conflict', () => { + elm.dispatchEvent( + newActionEvent({ + old: { + parent, + element, + reference, + }, + new: { + parent: elm.doc!.querySelector('VoltageLevel[name="J1"]')!, reference: null, }, }) ); - expect(parent.querySelector('child1')).to.be.null; - expect(elm.doc!.querySelector('parent2 > child1')).to.not.be.null; + expect(parent.querySelector('Bay[name="Q01"]')).to.be.null; + expect(elm.doc!.querySelector('VoltageLevel[name="J1"] > Bay[name="Q01"]')) + .to.not.be.null; + expect( + elm.doc!.querySelector('VoltageLevel[name="J1"] > Bay[name="Q01"]') + ?.nextElementSibling + ).to.be.null; }); it('carries out subactions sequentially on receiving a ComplexAction', () => { - const child3 = elm.doc!.createElement('child3'); + const child3 = elm.doc!.createElement('newBay'); elm.dispatchEvent( newActionEvent({ title: 'Test complex action', @@ -101,14 +218,15 @@ describe('EditingElement', () => { reference, }, new: { - parent: elm.doc!.querySelector('parent2')!, + parent: elm.doc!.querySelector('VoltageLevel[name="J1"]')!, reference: null, }, }, ], }) ); - expect(parent.querySelector('child1')).to.be.null; - expect(elm.doc!.querySelector('parent2 > child3')).to.not.be.null; + expect(parent.querySelector('Bay[name="Q01"]')).to.be.null; + expect(elm.doc!.querySelector('VoltageLevel[name="J1"] > newBay')).to.not.be + .null; }); });