@@ -49,7 +49,7 @@ snapshots["subnetwork-editor wizarding integration edit/add Subnetwork wizard lo
+
+
+ TrainingIEC61850
+
+
+
+
+
+
+ 100.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/testfiles/valid2003.scd b/test/testfiles/valid2003.scd
index bd2b924c12..61e270ce98 100644
--- a/test/testfiles/valid2003.scd
+++ b/test/testfiles/valid2003.scd
@@ -36,7 +36,7 @@
-
+
100.0
diff --git a/test/unit/editors/communication/SubNetwork.test.ts b/test/unit/editors/communication/SubNetwork.test.ts
deleted file mode 100644
index d4150677c9..0000000000
--- a/test/unit/editors/communication/SubNetwork.test.ts
+++ /dev/null
@@ -1,217 +0,0 @@
-import { fixture, html, expect } from '@open-wc/testing';
-
-import '../../../../src/wizard-textfield.js';
-import {
- createSubNetworkAction,
- updateSubNetworkAction,
-} from '../../../../src/editors/communication/subnetwork-editor.js';
-import {
- WizardInput,
- isCreate,
- isUpdate,
- isDelete,
-} from '../../../../src/foundation.js';
-
-describe('SubNetworkEditor', () => {
- describe('with no nulled properties', () => {
- const noOp = () => {
- return;
- };
- const newWizard = (done = noOp) => {
- const element = document.createElement('mwc-dialog');
- element.close = done;
- return element;
- };
-
- let inputs: WizardInput[];
- beforeEach(async () => {
- inputs = await Promise.all(
- ['name', 'desc', 'type', 'BitRate'].map(
- label =>
- >(
- fixture(
- html` `
- )
- )
- )
- );
- });
-
- describe('has a createAction that', () => {
- let parent: Element;
- beforeEach(() => {
- parent = new DOMParser().parseFromString(
- ' ',
- 'application/xml'
- ).documentElement;
- });
-
- it('returns a WizardAction which returns a Create EditorAction', () => {
- const wizardAction = createSubNetworkAction(parent);
- expect(wizardAction(inputs, newWizard())[0]).to.satisfy(isCreate);
- });
- });
-
- describe('has an updateAction that', () => {
- let element: Element;
- beforeEach(() => {
- element = new DOMParser().parseFromString(
- ' ',
- 'application/xml'
- ).documentElement;
- });
-
- describe('with missing child element BitRate', () => {
- let element: Element;
- beforeEach(() => {
- element = new DOMParser().parseFromString(
- ' ',
- 'application/xml'
- ).documentElement;
- });
-
- it('returns a WizardAction which retruns two EditorActions', () => {
- const wizardAction = updateSubNetworkAction(element);
- expect(wizardAction(inputs, newWizard()).length).to.equal(2);
- });
-
- it('returns a WizardAction with the first returned EditorAction beeing an Update', () => {
- const wizardAction = updateSubNetworkAction(element);
- expect(wizardAction(inputs, newWizard())[0]).to.satisfy(isUpdate);
- });
-
- it('returns a WizardAction with the second returned EditorAction beeing a Create', () => {
- const wizardAction = updateSubNetworkAction(element);
- expect(wizardAction(inputs, newWizard())[1]).to.satisfy(isCreate);
- });
- });
-
- describe('with present child element BitRate', () => {
- let element: Element;
- beforeEach(() => {
- element = new DOMParser().parseFromString(
- `
- 100
- `,
- 'application/xml'
- ).documentElement;
- });
-
- it('returns a WizardAction which returns two EditorActions', () => {
- const wizardAction = updateSubNetworkAction(element);
- expect(wizardAction(inputs, newWizard()).length).to.equal(2);
- });
-
- it('returns a WizardAction with the first returned EditorAction beeing an Update', () => {
- const wizardAction = updateSubNetworkAction(element);
- expect(wizardAction(inputs, newWizard())[0]).to.satisfy(isUpdate);
- });
-
- it('returns a WizardAction with the second returned EditorAction beeing a Update', () => {
- const wizardAction = updateSubNetworkAction(element);
- expect(wizardAction(inputs, newWizard())[1]).to.satisfy(isUpdate);
- });
- });
-
- describe('with no change in element SubNetwork but changes in the child element BitRate', () => {
- let element: Element;
- beforeEach(() => {
- element = new DOMParser().parseFromString(
- `
- 100
- `,
- 'application/xml'
- ).documentElement;
- });
-
- it('returns a WizardAction which returns one EditorActions', () => {
- const wizardAction = updateSubNetworkAction(element);
- expect(wizardAction(inputs, newWizard()).length).to.equal(1);
- });
-
- it('returns a WizardAction with the first returned EditorAction beeing an Update', () => {
- const wizardAction = updateSubNetworkAction(element);
- expect(wizardAction(inputs, newWizard())[0]).to.satisfy(isUpdate);
- });
- });
-
- describe('with no change in SubNetwork nor BitRate', () => {
- let element: Element;
- beforeEach(() => {
- element = new DOMParser().parseFromString(
- ' ',
- 'application/xml'
- ).documentElement;
- });
-
- it('returns a WizardAction with an empty EditorActions array', () => {
- const wizardAction = updateSubNetworkAction(element);
- expect(wizardAction(inputs, newWizard()).length).to.equal(0);
- });
- });
- });
- });
-
- describe('with nulled properties', () => {
- const noOp = () => {
- return;
- };
- const newWizard = (done = noOp) => {
- const element = document.createElement('mwc-dialog');
- element.close = done;
- return element;
- };
-
- let inputs: WizardInput[];
- beforeEach(async () => {
- inputs = await Promise.all(
- ['name', 'desc', 'type', 'BitRate'].map(
- label =>
- >(
- fixture(
- html` `
- )
- )
- )
- );
- });
-
- describe('has an updateAction that', () => {
- describe('with present child element Voltage', () => {
- let element: Element;
- beforeEach(async () => {
- element = new DOMParser().parseFromString(
- `
- 100
- `,
- 'application/xml'
- ).documentElement;
-
- inputs[3] = await fixture(html` `);
- });
-
- it('returns a WizardAction which returns two EditorActions', () => {
- const wizardAction = updateSubNetworkAction(element);
- expect(wizardAction(inputs, newWizard()).length).to.equal(2);
- });
-
- it('returns a WizardAction with the first returned EditorAction beeing an Update', () => {
- const wizardAction = updateSubNetworkAction(element);
- expect(wizardAction(inputs, newWizard())[0]).to.satisfy(isUpdate);
- });
-
- it('returns a WizardAction with the second returned EditorAction beeing a Delete', () => {
- const wizardAction = updateSubNetworkAction(element);
- expect(wizardAction(inputs, newWizard())[1]).to.satisfy(isDelete);
- });
- });
- });
- });
-});
diff --git a/test/unit/editors/communication/__snapshots__/subnetwork-editor.test.snap.js b/test/unit/editors/communication/__snapshots__/subnetwork-editor.test.snap.js
index 4f71771fea..a0e9c3362a 100644
--- a/test/unit/editors/communication/__snapshots__/subnetwork-editor.test.snap.js
+++ b/test/unit/editors/communication/__snapshots__/subnetwork-editor.test.snap.js
@@ -2,40 +2,41 @@
export const snapshots = {};
snapshots["subnetwork-editor looks like the latest snapshot"] =
-`
-
- StationBus — desc
- (8-MMS—100.0b/s)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- IED1
-
-
-
-
-
-
+
+
+
+
+
-
+
`;
/* end snapshot subnetwork-editor looks like the latest snapshot */
diff --git a/test/unit/editors/communication/subnetwork-editor.test.ts b/test/unit/editors/communication/subnetwork-editor.test.ts
index 18b1152256..a6ef4ebe3d 100644
--- a/test/unit/editors/communication/subnetwork-editor.test.ts
+++ b/test/unit/editors/communication/subnetwork-editor.test.ts
@@ -5,16 +5,17 @@ import { SubNetworkEditor } from '../../../../src/editors/communication/subnetwo
describe('subnetwork-editor', () => {
let element: SubNetworkEditor;
- let validSCL: XMLDocument;
+ let subNetwork: Element;
+
beforeEach(async () => {
- validSCL = await fetch('/test/testfiles/valid2007B4.scd')
+ const validSCL = await fetch('/test/testfiles/communication.scd')
.then(response => response.text())
.then(str => new DOMParser().parseFromString(str, 'application/xml'));
+
+ subNetwork = validSCL.querySelector('SubNetwork')!;
element =
(
await fixture(
- html` `
+ html` `
)
);
});
@@ -22,13 +23,46 @@ describe('subnetwork-editor', () => {
it('has a name property', () =>
expect(element).to.have.property('name', 'StationBus'));
+ it('indicates missing required name as UNDEFINED', async () => {
+ subNetwork.removeAttribute('name');
+ await element.requestUpdate();
+
+ expect(element).to.have.property('name', 'UNDEFINED');
+ });
+
it('has a desc property', () =>
expect(element).to.have.property('desc', 'desc'));
it('has a type property', () =>
expect(element).to.have.property('type', '8-MMS'));
- it('looks like the latest snapshot', async () => {
- await expect(element).shadowDom.to.equalSnapshot();
+ it('return null with missing type attribute', async () => {
+ subNetwork.removeAttribute('type');
+ await element.requestUpdate();
+
+ expect(element).to.have.property('type', null);
+ });
+
+ it('has a BitRate property', () =>
+ expect(element).to.have.property('bitrate', '100.0b/s'));
+
+ it('includes multiplier to bitrate property', async () => {
+ const bitrate = subNetwork.querySelector('BitRate');
+ bitrate?.setAttribute('multiplier', 'M');
+ await element.requestUpdate();
+
+ expect(element).to.have.property('bitrate', '100.0 Mb/s');
});
+
+ it('returns null with missing BitRate content event though BitRate exist as element', async () => {
+ const bitrate = subNetwork.querySelector('BitRate');
+ bitrate!.textContent = null;
+ bitrate?.setAttribute('multiplier', 'M');
+ await element.requestUpdate();
+
+ expect(element).to.have.property('bitrate', null);
+ });
+
+ it('looks like the latest snapshot', async () =>
+ await expect(element).shadowDom.to.equalSnapshot());
});
diff --git a/test/unit/wizards/__snapshots__/subnetwork.test.snap.js b/test/unit/wizards/__snapshots__/subnetwork.test.snap.js
new file mode 100644
index 0000000000..867ece682d
--- /dev/null
+++ b/test/unit/wizards/__snapshots__/subnetwork.test.snap.js
@@ -0,0 +1,238 @@
+/* @web/test-runner snapshot v1 */
+export const snapshots = {};
+
+snapshots["Wizards for SCL element SubNetwork include an edit wizard that with existing BitRate child element looks like the latest snapshot"] =
+`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+/* end snapshot Wizards for SCL element SubNetwork include an edit wizard that with existing BitRate child element looks like the latest snapshot */
+
+snapshots["Wizards for SCL element SubNetwork include an edit wizard that with missing BitRate child element looks like the latest snapshot"] =
+`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+/* end snapshot Wizards for SCL element SubNetwork include an edit wizard that with missing BitRate child element looks like the latest snapshot */
+
+snapshots["Wizards for SCL element SubNetwork include an edit wizard that looks like the latest snapshot"] =
+`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+/* end snapshot Wizards for SCL element SubNetwork include an edit wizard that looks like the latest snapshot */
+
+snapshots["Wizards for SCL element SubNetwork include an create wizard that looks like the latest snapshot"] =
+`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+/* end snapshot Wizards for SCL element SubNetwork include an create wizard that looks like the latest snapshot */
+
diff --git a/test/unit/wizards/subnetwork.test.ts b/test/unit/wizards/subnetwork.test.ts
new file mode 100644
index 0000000000..9e694f2a0e
--- /dev/null
+++ b/test/unit/wizards/subnetwork.test.ts
@@ -0,0 +1,359 @@
+import { expect, fixture, html } from '@open-wc/testing';
+import { SinonSpy, spy } from 'sinon';
+
+import '../../mock-wizard.js';
+import { MockWizard } from '../../mock-wizard.js';
+
+import { WizardTextField } from '../../../src/wizard-textfield.js';
+import {
+ isCreate,
+ isDelete,
+ WizardInput,
+ isUpdate,
+ Update,
+ Delete,
+ Create,
+} from '../../../src/foundation.js';
+import {
+ createSubNetworkWizard,
+ editSubNetworkWizard,
+} from '../../../src/wizards/subnetwork.js';
+
+describe('Wizards for SCL element SubNetwork', () => {
+ let doc: XMLDocument;
+ let element: MockWizard;
+ let inputs: WizardInput[];
+ let input: WizardInput | undefined;
+ let primaryAction: HTMLElement;
+
+ let actionEvent: SinonSpy;
+
+ beforeEach(async () => {
+ element = await fixture(html` `);
+
+ actionEvent = spy();
+ window.addEventListener('editor-action', actionEvent);
+ });
+
+ describe('include an edit wizard that', () => {
+ beforeEach(async () => {
+ doc = await fetch('/test/testfiles/valid2003.scd')
+ .then(response => response.text())
+ .then(str => new DOMParser().parseFromString(str, 'application/xml'));
+ });
+
+ describe('with existing BitRate child element', () => {
+ beforeEach(async () => {
+ const wizard = editSubNetworkWizard(doc.querySelector('SubNetwork')!);
+ element.workflow.push(() => wizard);
+ await element.requestUpdate();
+
+ inputs = Array.from(element.wizardUI.inputs);
+
+ primaryAction = (
+ element.wizardUI.dialog?.querySelector(
+ 'mwc-button[slot="primaryAction"]'
+ )
+ );
+ });
+
+ it('looks like the latest snapshot', async () => {
+ await expect(element.wizardUI.dialog).dom.to.equalSnapshot();
+ });
+
+ it('does not edit any attributes with unchanged wizard inputs', async () => {
+ primaryAction.click();
+ await element.requestUpdate();
+ expect(actionEvent).to.not.have.been.called;
+ });
+
+ it('triggers an editor action to update name attribute', async () => {
+ input = inputs.find(input => input.label === 'name');
+ input.value = 'newSubNetName';
+ await input.requestUpdate();
+
+ primaryAction.click();
+ await element.requestUpdate();
+
+ expect(actionEvent).to.be.calledOnce;
+ expect(actionEvent.args[0][0].detail.action).to.satisfy(isUpdate);
+
+ const updateAction = actionEvent.args[0][0].detail.action;
+ expect(updateAction.old.element).to.have.a.attribute(
+ 'name',
+ 'StationBus'
+ );
+ expect(updateAction.new.element).to.have.a.attribute(
+ 'name',
+ 'newSubNetName'
+ );
+ });
+
+ it('triggers an editor action to update desc attribute', async () => {
+ input = inputs.find(input => input.label === 'desc');
+ await input.requestUpdate();
+
+ (input).nullSwitch?.click();
+ input.value = 'myNewSubNetworkDesc';
+ await input.requestUpdate();
+
+ primaryAction.click();
+ await element.requestUpdate();
+
+ expect(actionEvent).to.be.calledOnce;
+ expect(actionEvent.args[0][0].detail.action).to.satisfy(isUpdate);
+
+ const updateAction = actionEvent.args[0][0].detail.action;
+ expect(updateAction.old.element).to.not.have.a.attribute('desc');
+ expect(updateAction.new.element).to.have.a.attribute(
+ 'desc',
+ 'myNewSubNetworkDesc'
+ );
+ });
+
+ it('triggers an editor action to update type attribute', async () => {
+ input = inputs.find(input => input.label === 'type');
+ input.value = 'myNewSubNetType';
+ await input.requestUpdate();
+
+ primaryAction.click();
+ await element.requestUpdate();
+
+ expect(actionEvent).to.be.calledOnce;
+ expect(actionEvent.args[0][0].detail.action).to.satisfy(isUpdate);
+
+ const updateAction = actionEvent.args[0][0].detail.action;
+ expect(updateAction.old.element).to.have.a.attribute('type', '8-MMS');
+ expect(updateAction.new.element).to.have.a.attribute(
+ 'type',
+ 'myNewSubNetType'
+ );
+ });
+
+ it('triggers an editor action to update BitRate element', async () => {
+ input = (
+ inputs.find(input => input.label === 'BitRate')
+ );
+ input.value = '200.';
+ (input).multiplier = 'M';
+ await input.requestUpdate();
+
+ primaryAction.click();
+ await element.requestUpdate();
+
+ expect(actionEvent).to.be.calledOnce;
+ expect(actionEvent.args[0][0].detail.action).to.satisfy(isUpdate);
+
+ const updateAction = actionEvent.args[0][0].detail.action;
+ expect(updateAction.old.element.innerHTML.trim()).to.equal('100.0');
+ expect(updateAction.old.element).to.not.have.attribute('multiplier');
+ expect(updateAction.new.element.innerHTML.trim()).to.equal('200.');
+ expect(updateAction.new.element).to.have.attribute('multiplier', 'M');
+ });
+
+ it('triggers an editor action to remove BitRate element', async () => {
+ input = (
+ inputs.find(input => input.label === 'BitRate')
+ );
+ await input.requestUpdate();
+
+ (input).nullSwitch?.click();
+ await input.requestUpdate();
+
+ primaryAction.click();
+ await element.requestUpdate();
+
+ expect(actionEvent).to.be.calledOnce;
+ expect(actionEvent.args[0][0].detail.action).to.satisfy(isDelete);
+
+ const updateAction = actionEvent.args[0][0].detail.action;
+ expect(updateAction.old.element.innerHTML.trim()).to.equal('100.0');
+ expect(updateAction.old.element).to.not.have.attribute('multiplier');
+ });
+ });
+
+ describe('with missing BitRate child element', () => {
+ beforeEach(async () => {
+ const wizard = editSubNetworkWizard(
+ doc.querySelector('SubNetwork[name="ProcessBus"]')!
+ );
+ element.workflow.push(() => wizard);
+ await element.requestUpdate();
+
+ inputs = Array.from(element.wizardUI.inputs);
+
+ primaryAction = (
+ element.wizardUI.dialog?.querySelector(
+ 'mwc-button[slot="primaryAction"]'
+ )
+ );
+ });
+
+ it('looks like the latest snapshot', async () => {
+ await expect(element.wizardUI.dialog).dom.to.equalSnapshot();
+ });
+
+ it('triggers an editor action to create a complete BitRate element', async () => {
+ input = (
+ inputs.find(input => input.label === 'BitRate')
+ );
+ await input.requestUpdate();
+
+ (input).nullSwitch?.click();
+ (input).value = '100.0';
+ (input).multiplier = 'M';
+
+ primaryAction.click();
+ await element.requestUpdate();
+
+ expect(actionEvent).to.be.calledOnce;
+ expect(actionEvent.args[0][0].detail.action).to.satisfy(isCreate);
+
+ const updateAction = actionEvent.args[0][0].detail.action;
+ expect(updateAction.new.element.innerHTML.trim()).to.equal('100.0');
+ expect(updateAction.new.element).to.have.attribute('multiplier', 'M');
+ });
+
+ it('triggers an editor action to create BitRate element with multiplier only', async () => {
+ input = (
+ inputs.find(input => input.label === 'BitRate')
+ );
+ await input.requestUpdate();
+
+ (input).nullSwitch?.click();
+ (input).multiplier = 'M';
+
+ primaryAction.click();
+ await element.requestUpdate();
+
+ expect(actionEvent).to.be.calledOnce;
+ expect(actionEvent.args[0][0].detail.action).to.satisfy(isCreate);
+
+ const updateAction = actionEvent.args[0][0].detail.action;
+ expect(updateAction.new.element.innerHTML.trim()).to.equal('');
+ expect(updateAction.new.element).to.have.attribute('multiplier');
+ });
+
+ it('triggers an editor action to create BitRate element with bit rate only', async () => {
+ input = (
+ inputs.find(input => input.label === 'BitRate')
+ );
+ await input.requestUpdate();
+
+ (input).nullSwitch?.click();
+ (input).value = '100.0';
+
+ primaryAction.click();
+ await element.requestUpdate();
+
+ expect(actionEvent).to.be.calledOnce;
+ expect(actionEvent.args[0][0].detail.action).to.satisfy(isCreate);
+
+ const updateAction = actionEvent.args[0][0].detail.action;
+ expect(updateAction.new.element.innerHTML.trim()).to.equal('100.0');
+ expect(updateAction.new.element).to.not.have.attribute('multiplier');
+ });
+ });
+ });
+
+ describe('include an create wizard that', () => {
+ beforeEach(async () => {
+ doc = await fetch('/test/testfiles/valid2003.scd')
+ .then(response => response.text())
+ .then(str => new DOMParser().parseFromString(str, 'application/xml'));
+
+ const wizard = createSubNetworkWizard(
+ doc.querySelector('Communication')!
+ );
+ element.workflow.push(() => wizard);
+ await element.requestUpdate();
+
+ inputs = Array.from(element.wizardUI.inputs);
+
+ primaryAction = (
+ element.wizardUI.dialog?.querySelector(
+ 'mwc-button[slot="primaryAction"]'
+ )
+ );
+ });
+
+ it('looks like the latest snapshot', async () => {
+ await expect(element.wizardUI.dialog).dom.to.equalSnapshot();
+ });
+
+ it('does not allow creating SubNetwork with empty name attribute', async () => {
+ input = inputs.find(input => input.label === 'name');
+ input.value = '';
+ await input.requestUpdate();
+
+ primaryAction.click();
+ await element.requestUpdate();
+
+ expect(actionEvent).to.not.be.called;
+ });
+
+ it('triggers an editor action to create SubNetwork element including BitRate', async () => {
+ input = inputs.find(input => input.label === 'name');
+ input.value = 'myNewSubNetworkName';
+ await input.requestUpdate();
+
+ primaryAction.click();
+ await element.requestUpdate();
+
+ expect(actionEvent).to.be.calledOnce;
+ expect(actionEvent.args[0][0].detail.action).to.satisfy(isCreate);
+
+ const updateAction = actionEvent.args[0][0].detail.action;
+ expect(updateAction.new.element).to.have.a.attribute(
+ 'name',
+ 'myNewSubNetworkName'
+ );
+ expect(updateAction.new.element).to.have.a.attribute('desc', '');
+ expect(updateAction.new.element).to.have.a.attribute('type', '8-MMS');
+ expect(updateAction.new.element.querySelector('BitRate')).to.exist;
+ expect(
+ updateAction.new.element.querySelector('BitRate')
+ ).to.have.attribute('multiplier', 'M');
+ expect(
+ updateAction.new.element.querySelector('BitRate')?.textContent?.trim()
+ ).to.equal('100');
+ });
+
+ it('triggers an editor action to create SubNetwork element excluding non required /BitRate', async () => {
+ const name = (
+ inputs.find(input => input.label === 'name')
+ );
+ const desc = (
+ inputs.find(input => input.label === 'desc')
+ );
+ const type = (
+ inputs.find(input => input.label === 'type')
+ );
+ const bitrate = (
+ inputs.find(input => input.label === 'BitRate')
+ );
+ await element.requestUpdate();
+
+ desc.nullSwitch?.click();
+ type.nullSwitch?.click();
+ bitrate.nullSwitch?.click();
+ name.value = 'myNewSubNetworkName';
+ await name.requestUpdate();
+
+ primaryAction.click();
+ await element.requestUpdate();
+
+ expect(actionEvent).to.be.calledOnce;
+ expect(actionEvent.args[0][0].detail.action).to.satisfy(isCreate);
+
+ const updateAction = actionEvent.args[0][0].detail.action;
+ expect(updateAction.new.element).to.have.a.attribute(
+ 'name',
+ 'myNewSubNetworkName'
+ );
+ expect(updateAction.new.element).to.not.have.a.attribute('desc');
+ expect(updateAction.new.element).to.not.have.a.attribute('type');
+ expect(updateAction.new.element.querySelector('BitRate')).to.not.exist;
+ });
+ });
+});