@openenergytools/open-scd-core
Version:
The core component of OpenSCD
336 lines (294 loc) • 12.3 kB
text/typescript
import { visualDiff } from '@web/test-runner-visual-regression';
import type { IconButton } from '@material/mwc-icon-button';
import type { ListItem } from '@material/mwc-list/mwc-list-item.js';
import './open-scd.js';
import { expect } from '@open-wc/testing';
import type { OpenSCD } from './open-scd.js';
import { Edit, newEditEvent, newOpenEvent } from './foundation.js';
import { allLocales } from './locales.js';
const factor = window.process && process.env.CI ? 4 : 2;
function timeout(ms: number) {
return new Promise(res => setTimeout(res, ms * factor));
}
mocha.timeout(2000 * factor);
const doc = new DOMParser().parseFromString(
`<testdoc></testdoc>`,
'application/xml'
);
let editor: OpenSCD;
beforeEach(() => {
editor = document.createElement('open-scd');
document.body.prepend(editor);
});
afterEach(() => {
editor.remove();
});
it(`changes locales on attribute change`, async () => {
editor.setAttribute('locale', 'invalid');
await editor.updateComplete;
expect(editor).to.have.property('locale', 'en');
editor.setAttribute('locale', 'de');
await editor.updateComplete;
await timeout(180);
await editor.updateComplete;
expect(editor).to.have.property('locale', 'de');
});
allLocales.forEach(lang =>
describe(`translated to ${lang}`, () => {
beforeEach(async () => {
editor.setAttribute('locale', lang);
await editor.updateComplete;
expect(editor).to.have.property('locale', lang);
});
it(`displays a top app bar`, async () => {
await editor.updateComplete;
await timeout(20);
await visualDiff(editor, `app-bar-${lang}`);
});
it(`displays a menu on button click`, async () => {
await editor.updateComplete;
editor.shadowRoot
?.querySelector<IconButton>('mwc-icon-button[icon="menu"]')
?.click();
await editor.updateComplete;
await timeout(200);
await visualDiff(editor, `menu-drawer-${lang}`);
});
it(`displays a current document title`, async () => {
await editor.updateComplete;
editor.dispatchEvent(newOpenEvent(doc, 'test.xml'));
await editor.updateComplete;
await timeout(20);
await visualDiff(editor, `document-name-${lang}`);
});
it(`shows a log screen`, async () => {
await editor.updateComplete;
editor.shadowRoot
?.querySelector<IconButton>('mwc-icon-button[icon="menu"]')
?.click();
editor.shadowRoot
?.querySelector<ListItem>('mwc-list-item:last-child')
?.click();
await editor.updateComplete;
await timeout(200);
await visualDiff(editor, `log-screen-${lang}`);
});
it(`shows log entries`, async () => {
const parent = doc.documentElement;
const node = doc.createElement('test');
const reference = doc.querySelector('testchild');
editor.dispatchEvent(newEditEvent({ parent, node, reference }));
editor.dispatchEvent(newEditEvent({ parent, node, reference: null }));
const element = doc.querySelector('testdoc')!;
editor.dispatchEvent(
newEditEvent({
element,
attributes: {
name: 'A2',
desc: null,
'myns:attr': {
value: 'namespaced value',
namespaceURI: 'http://example.org/myns',
},
},
})
);
editor.dispatchEvent(newEditEvent({ node }));
editor.dispatchEvent(
newEditEvent(
[
{ parent, node, reference },
{ parent, node, reference: null },
'invalid edit' as unknown as Edit,
],
{ title: 'User Defined Log Title' }
)
);
editor.dispatchEvent(newEditEvent({ node }, { squash: true }));
await editor.updateComplete;
editor.shadowRoot
?.querySelector<IconButton>('mwc-icon-button[icon="history"]')
?.click();
await editor.updateComplete;
await timeout(200);
await visualDiff(editor, `log-entries-${lang}`);
editor.shadowRoot
?.querySelector<IconButton>('mwc-icon-button[icon="undo"]')
?.click();
await editor.updateComplete;
editor.shadowRoot
?.querySelector<IconButton>('mwc-icon-button[icon="undo"]')
?.click();
await editor.updateComplete;
editor.shadowRoot
?.querySelector<IconButton>('mwc-icon-button[icon="undo"]')
?.click();
await editor.updateComplete;
editor.shadowRoot
?.querySelector<IconButton>('mwc-icon-button[icon="undo"]')
?.click();
await editor.updateComplete;
editor.dispatchEvent(
new KeyboardEvent('keydown', {
key: 'z',
ctrlKey: true,
bubbles: true,
composed: true,
})
);
editor.dispatchEvent(
new KeyboardEvent('keydown', {
key: 'y',
ctrlKey: false,
bubbles: true,
composed: true,
})
);
editor.dispatchEvent(
new KeyboardEvent('keydown', {
key: 'X',
ctrlKey: true,
bubbles: true,
composed: true,
})
);
await editor.updateComplete;
await timeout(100);
await visualDiff(editor, `log-entries-undone-${lang}`);
editor.shadowRoot
?.querySelector<IconButton>('mwc-icon-button[icon="redo"]')
?.click();
await editor.updateComplete;
editor.shadowRoot
?.querySelector<IconButton>('mwc-icon-button[icon="redo"]')
?.click();
await editor.updateComplete;
await timeout(100);
await visualDiff(editor, `log-entries-redone-${lang}`);
});
describe('with menu plugins loaded', () => {
beforeEach(async () => {
editor.plugins = {
editor: [],
menu: [
{
name: 'Test Menu Plugin',
translations: { de: 'Test Menü Erweiterung' },
src: 'data:text/javascript;charset=utf-8,export%20default%20class%20TestPlugin%20extends%20HTMLElement%20%7B%0D%0A%20%20async%20run%28%29%20%7B%0D%0A%20%20%20%20return%20false%3B%0D%0A%20%20%7D%0D%0A%7D',
icon: 'android',
active: true,
requireDoc: true,
},
{
name: 'Test Menu Plugin 2',
src: 'data:text/javascript;charset=utf-8,export%20default%20class%20TestPlugin%20extends%20HTMLElement%20%7B%0D%0A%20%20async%20run%28%29%20%7B%0D%0A%20%20%20%20this.dispatchEvent%28new%20CustomEvent%28%27oscd-open%27%2C%20%7Bdetail%3A%20%7BdocName%3A%20%27testDoc%27%2C%20doc%3A%20window.document%7D%2C%20bubbles%3A%20true%2C%20composed%3A%20true%7D%29%29%3B%0D%0A%20%20%7D%0D%0A%7D',
icon: 'polymer',
active: true,
requireDoc: false,
},
{
name: 'Test Menu Plugin 3',
translations: { de: 'Test Menü Erweiterung 3' },
src: 'data:text/javascript;charset=utf-8,export%20default%20class%20BrokenTestPlugin%20extends%20HTMLElement%20%7B%0D%0A%20%20%2F%2F%20oh%20NO%21%20There%27s%20no%20run%20method%21%0D%0A%7D',
icon: 'dry',
active: true,
requireDoc: false,
},
{
name: 'Test Menu Plugin 4',
translations: { de: 'Test Menü Erweiterung 4' },
src: 'data:text/javascript;charset=utf-8,export%20default%20class%20BrokenTestPlugin%20extends%20HTMLElement%20%7B%0D%0A%20%20%2F%2F%20oh%20no%21%20There%27s%20no%20run%20method%21%0D%0A%7D',
icon: 'translate',
active: false,
requireDoc: true,
},
],
};
await editor.updateComplete;
});
it('displays menu plugins in the menu', async () => {
editor.shadowRoot
?.querySelector<IconButton>('mwc-icon-button[icon="menu"]')
?.click();
await editor.updateComplete;
await timeout(200);
await visualDiff(editor, `menu-plugins-${lang}`);
});
it('triggers menu plugins on menu entry click', async () => {
editor.shadowRoot
?.querySelector<IconButton>('mwc-icon-button[icon="menu"]')
?.click();
await editor.updateComplete;
await timeout(200);
editor.menuUI
?.querySelector<IconButton>('mwc-list-item:nth-of-type(2)')
?.click();
editor.menuUI
?.querySelector<IconButton>('mwc-list-item:nth-of-type(3)')
?.click();
await editor.updateComplete;
await timeout(200);
expect(editor.docName).to.equal('testDoc');
await editor.updateComplete;
await visualDiff(editor, `menu-plugins-triggered-${lang}`);
});
});
describe('with editor plugins loaded', () => {
beforeEach(async () => {
editor.plugins = {
menu: [],
editor: [
{
name: 'Test Editor Plugin',
translations: { de: 'Test Editor Erweiterung' },
src: 'data:text/javascript;charset=utf-8,export%20default%20class%20TestEditorPlugin%20extends%20HTMLElement%20%7B%0D%0A%20%20constructor%20%28%29%20%7B%20super%28%29%3B%20this.innerHTML%20%3D%20%60%3Cp%3ETest%20Editor%20Plugin%3C%2Fp%3E%60%3B%20%7D%0D%0A%7D',
icon: 'edit',
active: true,
requireDoc: true,
},
{
name: 'Test Editor Plugin 2',
src: 'data:text/javascript;charset=utf-8,export%20default%20class%20TestEditorPlugin2%20extends%20HTMLElement%20%7B%0D%0A%20%20constructor%20%28%29%20%7B%20super%28%29%3B%20this.innerHTML%20%3D%20%60%3Cp%3ETest%20Editor%20Plugin%202%3C%2Fp%3E%60%3B%20%7D%0D%0A%7D',
icon: 'android',
active: true,
requireDoc: false,
},
{
name: 'Test Editor Plugin 3',
translations: { de: 'Test Editor Erweiterung 3' },
src: 'data:text/javascript;charset=utf-8,export%20default%20class%20EditorPluginTest3%20extends%20HTMLElement%20%7B%0D%0A%20%20%20%20constructor%20%28%29%20%7B%0D%0A%09%2F%2F%20Create%20a%20shadow%20root%0D%0A%09this.attachShadow%28%7B%20mode%3A%20%22open%22%20%7D%29%3B%20%2F%2F%20sets%20and%20returns%20%27this.shadowRoot%27%0D%0A%0D%0A%09const%20info%20%3D%20wrapper.appendChild%28document.createElement%28%22span%22%29%29%3B%0D%0A%09info.setAttribute%28%22class%22%2C%20%22info%22%29%3B%0D%0A%09%2F%2F%20Take%20attribute%20content%20and%20put%20it%20inside%20the%20info%20span%0D%0A%09info.textContent%20%3D%20this.getAttribute%28%22docName%22%29%20%7C%7C%20%27no%20docName%20Test3%27%3B%0D%0A%0D%0A%09%2F%2F%20attach%20the%20created%20elements%20to%20the%20shadow%20DOM%0D%0A%09this.shadowRoot.append%28style%2C%20info%29%3B%0D%0A%20%20%20%20%7D%0D%0A%7D%3B',
icon: 'polymer',
active: true,
requireDoc: false,
},
{
name: 'Test Editor Plugin 4',
translations: { de: 'Test Editor Erweiterung 4' },
src: 'data:text/javascript;charset=utf-8,export%20default%20class%20TestEditorPlugin4%20extends%20HTMLElement%20%7B%0D%0A%20%20constructor%20%28%29%20%7B%20super%28%29%3B%20this.innerHTML%20%3D%20%60%3Cp%3ETest%20Editor%20Plugin%204%3C%2Fp%3E%60%3B%20%7D%0D%0A%7D',
icon: 'edit',
active: false,
requireDoc: true,
},
],
};
await editor.updateComplete;
});
it('displays editor plugins', async () => {
await visualDiff(editor, `editor-plugins-${lang}`);
});
it('displays more tabs with a doc loaded', async () => {
editor.dispatchEvent(newOpenEvent(doc, 'test.xml'));
await editor.updateComplete;
await visualDiff(editor, `editor-plugins-with-doc-${lang}`);
});
it('changes active editor plugin on tab click', async () => {
editor.shadowRoot
?.querySelector<IconButton>('mwc-tab:nth-of-type(2)')
?.click();
await editor.updateComplete;
await timeout(120);
await visualDiff(editor, `editor-plugins-selected-${lang}`);
});
});
})
);