Skip to content

Commit d57db16

Browse files
committed
add unit tests
1 parent 87788d0 commit d57db16

4 files changed

Lines changed: 123 additions & 41 deletions

File tree

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/* eslint-disable no-unused-expressions */
2+
import { fixture, expect, html } from '@open-wc/testing';
3+
import { SinonSpy, spy } from 'sinon';
4+
import { DeleteDialog } from './delete-lnodetype-dialog.js';
5+
6+
customElements.define('delete-dialog', DeleteDialog);
7+
8+
describe('DeleteDialog', () => {
9+
let deleteDialog: DeleteDialog;
10+
let confirmSpy: SinonSpy;
11+
12+
beforeEach(async () => {
13+
confirmSpy = spy();
14+
15+
deleteDialog = await fixture(
16+
html`<delete-dialog
17+
.lnodeTypeId=${'MMXU$oscd$_c53e78191fabefa3'}
18+
.onConfirm=${confirmSpy}
19+
></delete-dialog>`
20+
);
21+
});
22+
23+
afterEach(async () => {
24+
deleteDialog.remove();
25+
});
26+
27+
it('displays the correct LNodeType ID in the message', () => {
28+
deleteDialog.show();
29+
expect(deleteDialog.shadowRoot?.textContent).to.include(
30+
'MMXU$oscd$_c53e78191fabefa3'
31+
);
32+
expect(deleteDialog.shadowRoot?.textContent).to.include('Confirm delete');
33+
expect(deleteDialog.shadowRoot?.textContent).to.include(
34+
'This action may have severe consequences'
35+
);
36+
});
37+
38+
it('should call onConfirm and close when Delete button is clicked', async () => {
39+
deleteDialog.show();
40+
await deleteDialog.updateComplete;
41+
await deleteDialog.dialog.updateComplete;
42+
43+
const buttons =
44+
deleteDialog.shadowRoot?.querySelectorAll('md-outlined-button');
45+
const deleteButton = Array.from(buttons || []).find(
46+
btn => btn.textContent?.trim() === 'Delete'
47+
) as HTMLElement;
48+
49+
expect(deleteButton).to.exist;
50+
deleteButton.click();
51+
await deleteDialog.updateComplete;
52+
await deleteDialog.dialog.updateComplete;
53+
54+
expect(confirmSpy.callCount).to.equal(1);
55+
});
56+
57+
it('should update displayed ID when lnodeTypeId property changes', async () => {
58+
deleteDialog.show();
59+
await deleteDialog.updateComplete;
60+
expect(deleteDialog.shadowRoot?.textContent).to.include(
61+
'MMXU$oscd$_c53e78191fabefa3'
62+
);
63+
64+
deleteDialog.lnodeTypeId = 'LLN0$oscd$_85c7ffbe25d80e63';
65+
await deleteDialog.updateComplete;
66+
expect(deleteDialog.shadowRoot?.textContent).to.include(
67+
'LLN0$oscd$_85c7ffbe25d80e63'
68+
);
69+
expect(deleteDialog.shadowRoot?.textContent).to.not.include(
70+
'MMXU$oscd$_c53e78191fabefa3'
71+
);
72+
});
73+
74+
it('should not call onConfirm when dialog is cancelled', async () => {
75+
deleteDialog.show();
76+
await deleteDialog.updateComplete;
77+
78+
const buttons =
79+
deleteDialog.shadowRoot?.querySelectorAll('md-outlined-button');
80+
const cancelButton = Array.from(buttons || []).find(
81+
btn => btn.textContent?.trim() === 'Cancel'
82+
) as HTMLElement;
83+
84+
cancelButton.click();
85+
await deleteDialog.updateComplete;
86+
87+
expect(confirmSpy.callCount).to.equal(0);
88+
});
89+
});
Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable @typescript-eslint/no-unused-vars */
22
import { ScopedElementsMixin } from '@open-wc/scoped-elements/lit-element.js';
33
import { LitElement, html, css } from 'lit';
4-
import { query, state } from 'lit/decorators.js';
4+
import { query, property } from 'lit/decorators.js';
55
import { MdDialog } from '@scopedelement/material-web/dialog/dialog.js';
66
import { MdOutlinedButton } from '@scopedelement/material-web/button/MdOutlinedButton.js';
77

@@ -11,16 +11,14 @@ export class DeleteDialog extends ScopedElementsMixin(LitElement) {
1111
'md-outlined-button': MdOutlinedButton,
1212
};
1313

14-
@query('md-dialog')
15-
dialog!: MdDialog;
14+
@property()
15+
onConfirm!: () => void;
1616

17-
@state()
17+
@property()
1818
lnodeTypeId: string = '';
1919

20-
@state()
21-
message: string = '';
22-
23-
onConfirm?: () => void;
20+
@query('md-dialog')
21+
dialog!: MdDialog;
2422

2523
get open() {
2624
return this.dialog?.open ?? false;
@@ -39,31 +37,24 @@ export class DeleteDialog extends ScopedElementsMixin(LitElement) {
3937
}
4038

4139
private handleConfirm() {
42-
if (this.onConfirm) {
43-
this.onConfirm();
44-
}
40+
this.onConfirm();
4541
this.close();
4642
}
4743

4844
render() {
4945
return html`
5046
<md-dialog>
51-
<div slot="headline">Confirm Delete</div>
52-
<form slot="content" id="form-delete" method="dialog">
53-
<div class="delete-content">
54-
<div class="message">${this.message}</div>
55-
</div>
56-
</form>
47+
<div slot="headline">Confirm delete</div>
48+
<div slot="content" class="delete-content">
49+
Are you sure you want to delete Logical Node Type ${this.lnodeTypeId}?
50+
This action may have severe consequences.
51+
</div>
5752
<div slot="actions">
58-
<md-outlined-button
59-
class="button close"
60-
form="form-delete"
61-
@click="${this.handleCancel}"
53+
<md-outlined-button class="button close" @click="${this.handleCancel}"
6254
>Cancel</md-outlined-button
6355
>
6456
<md-outlined-button
6557
class="button delete"
66-
form="form-delete"
6758
@click="${this.handleConfirm}"
6859
>Delete</md-outlined-button
6960
>
@@ -100,10 +91,6 @@ export class DeleteDialog extends ScopedElementsMixin(LitElement) {
10091
gap: 12px;
10192
}
10293
103-
.message {
104-
color: var(--oscd-base00);
105-
}
106-
10794
.button.close {
10895
--md-outlined-button-label-text-color: var(--oscd-accent-red);
10996
--md-outlined-button-hover-label-text-color: var(--oscd-accent-red);

foundation/utils.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,19 @@ export function filterSelection(
4040
return filteredTree;
4141
}
4242

43+
/**
44+
* Creates a clone of an LNodeType with only the DOs that are present in the selection.
45+
* DOs not included in the selection are removed from the cloned element.
46+
* @param lNodeType - The LNodeType element to filter
47+
* @param selection - The tree selection containing the DO names to keep
48+
* @returns A cloned LNodeType element containing only the selected DOs
49+
*/
4350
export function removeDOsNotInSelection(
4451
lNodeType: Element,
4552
selection: TreeSelection
4653
): Element {
4754
const clonedLNodeType = lNodeType.cloneNode(true) as Element;
4855

49-
// Remove DOs that are not in selection
5056
const dosToRemove: Element[] = [];
5157
Array.from(clonedLNodeType.querySelectorAll(':scope > DO')).forEach(
5258
doElement => {

scl-template-update.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import { MdIconButton } from '@scopedelement/material-web/iconbutton/MdIconButto
3030
import { CdcChildren } from '@openscd/scl-lib/dist/tDataTypeTemplates/nsdToJson.js';
3131

3232
import { AddDataObjectDialog } from './components/add-data-object-dialog.js';
33-
import { DeleteDialog } from './components/delete-dialog.js';
33+
import { DeleteDialog } from './components/delete-lnodetype-dialog.js';
3434
import { LNodeTypeSidebar } from './components/lnodetype-sidebar.js';
3535
import { SettingsDialog, UpdateSetting } from './components/settings-dialog.js';
3636
import {
@@ -397,16 +397,6 @@ export default class NsdTemplateUpdated extends ScopedElementsMixin(
397397
this.saveTemplates();
398398
}
399399

400-
private handleDeleteLNodeType(): void {
401-
if (!this.doc || !this.selectedLNodeType) return;
402-
403-
const lnID = this.selectedLNodeType.getAttribute('id');
404-
this.deleteDialog.lnodeTypeId = lnID || '';
405-
this.deleteDialog.message = `Are you sure you want to delete ${lnID}? This action can have severe consequences.`;
406-
this.deleteDialog.onConfirm = () => this.confirmDelete();
407-
this.deleteDialog.show();
408-
}
409-
410400
private confirmDelete(): void {
411401
if (!this.doc || !this.selectedLNodeType) return;
412402

@@ -618,11 +608,11 @@ export default class NsdTemplateUpdated extends ScopedElementsMixin(
618608
</md-outlined-button>
619609
<md-outlined-button
620610
?disabled=${!this.selectedLNodeType}
621-
@click=${this.handleDeleteLNodeType}
611+
@click=${() => this.deleteDialog.show()}
622612
class="button-delete"
623613
>
624614
<md-icon slot="icon">delete</md-icon>
625-
Delete Logical Node Type
615+
Delete LNode Type
626616
</md-outlined-button>
627617
<md-outlined-text-field
628618
id="lnodetype-desc"
@@ -651,7 +641,10 @@ export default class NsdTemplateUpdated extends ScopedElementsMixin(
651641
></lnodetype-sidebar>
652642
</div>
653643
${this.renderFab()} ${this.renderWarning()} ${this.renderChoice()}
654-
<delete-dialog></delete-dialog>
644+
<delete-dialog
645+
.lnodeTypeId=${this.selectedLNodeType?.getAttribute('id')}
646+
.onConfirm=${() => this.confirmDelete()}
647+
></delete-dialog>
655648
<add-data-object-dialog
656649
.cdClasses=${cdClasses}
657650
.tree=${this.treeUI?.tree}
@@ -714,6 +707,13 @@ export default class NsdTemplateUpdated extends ScopedElementsMixin(
714707
--md-outlined-button-hover-label-text-color: var(--oscd-accent-red);
715708
}
716709
710+
.button-delete {
711+
--md-outlined-button-label-text-color: var(--oscd-accent-red);
712+
--md-outlined-button-hover-label-text-color: var(--oscd-accent-red);
713+
--md-outlined-button-focus-label-text-color: var(--oscd-accent-red);
714+
--md-outlined-button-active-label-text-color: var(--oscd-accent-red);
715+
}
716+
717717
.button-delete md-icon {
718718
color: var(--oscd-accent-red);
719719
}

0 commit comments

Comments
 (0)