@schukai/monster 4.128.2 → 4.129.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/package.json +1 -1
  2. package/source/components/content/stylesheet/camera-capture.mjs +1 -1
  3. package/source/components/content/stylesheet/copy.mjs +1 -1
  4. package/source/components/content/viewer/stylesheet/message.mjs +1 -1
  5. package/source/components/datatable/columnbar.mjs +30 -3
  6. package/source/components/datatable/datatable.mjs +29 -1
  7. package/source/components/datatable/pagination.mjs +39 -1
  8. package/source/components/datatable/stylesheet/filter-controls-defaults.mjs +1 -1
  9. package/source/components/form/login.mjs +197 -0
  10. package/source/components/form/select.mjs +4 -4
  11. package/source/components/form/stylesheet/button-bar.mjs +1 -1
  12. package/source/components/form/stylesheet/confirm-button.mjs +1 -1
  13. package/source/components/form/stylesheet/context-error.mjs +1 -1
  14. package/source/components/form/stylesheet/context-help.mjs +1 -1
  15. package/source/components/form/stylesheet/digits.mjs +1 -1
  16. package/source/components/form/stylesheet/field-set.mjs +1 -1
  17. package/source/components/form/stylesheet/login.mjs +1 -1
  18. package/source/components/form/stylesheet/popper-button.mjs +1 -1
  19. package/source/components/form/stylesheet/select.mjs +1 -1
  20. package/source/components/form/tree-select.mjs +2 -2
  21. package/source/components/layout/stylesheet/popper.mjs +1 -1
  22. package/source/components/style/floating-ui.css +7 -0
  23. package/source/dom/customcontrol.mjs +1 -1
  24. package/source/dom/customelement.mjs +218 -16
  25. package/source/dom/updater.mjs +32 -12
  26. package/source/types/is.mjs +3 -0
  27. package/source/types/proxyobserver.mjs +10 -13
  28. package/source/types/version.mjs +1 -1
  29. package/test/cases/components/content/image-editor.mjs +98 -0
  30. package/test/cases/components/datatable/drag-scroll.mjs +218 -14
  31. package/test/cases/components/form/login.mjs +168 -0
  32. package/test/cases/components/form/select.mjs +94 -32
  33. package/test/cases/components/form/tree-select.mjs +22 -1
  34. package/test/cases/dom/customcontrol.mjs +44 -10
  35. package/test/cases/dom/customelement-initfromscripthost.mjs +22 -1
  36. package/test/cases/dom/customelement.mjs +83 -0
  37. package/test/cases/dom/updater.mjs +98 -0
  38. package/test/cases/monster.mjs +1 -1
  39. package/test/cases/types/proxyobserver.mjs +31 -0
  40. package/test/web/import.js +4 -0
  41. package/test/web/puppeteer.mjs +94 -71
  42. package/test/web/test.html +29 -2
  43. package/test/web/tests.js +28297 -15864
@@ -1,6 +1,7 @@
1
1
  import * as chai from "chai";
2
2
  import { chaiDom } from "../../../util/chai-dom.mjs";
3
3
  import { initJSDOM } from "../../../util/jsdom.mjs";
4
+ import { ResizeObserverMock } from "../../../util/resize-observer.mjs";
4
5
 
5
6
  const expect = chai.expect;
6
7
  chai.use(chaiDom);
@@ -32,6 +33,26 @@ function dispatchPointerEvent(target, type, options = {}) {
32
33
  return event;
33
34
  }
34
35
 
36
+ function mockScrollableElement(element, { clientWidth, scrollWidth, scrollLeft = 0 }) {
37
+ let currentScrollLeft = scrollLeft;
38
+
39
+ Object.defineProperty(element, "clientWidth", {
40
+ configurable: true,
41
+ value: clientWidth,
42
+ });
43
+ Object.defineProperty(element, "scrollWidth", {
44
+ configurable: true,
45
+ value: scrollWidth,
46
+ });
47
+ Object.defineProperty(element, "scrollLeft", {
48
+ configurable: true,
49
+ get: () => currentScrollLeft,
50
+ set: (value) => {
51
+ currentScrollLeft = value;
52
+ },
53
+ });
54
+ }
55
+
35
56
  describe("Datatable drag scroll", function () {
36
57
  before(async function () {
37
58
  await initJSDOM();
@@ -68,13 +89,9 @@ describe("Datatable drag scroll", function () {
68
89
  expect(scroll).to.exist;
69
90
  expect(cell).to.exist;
70
91
 
71
- Object.defineProperty(scroll, "clientWidth", {
72
- configurable: true,
73
- value: 200,
74
- });
75
- Object.defineProperty(scroll, "scrollWidth", {
76
- configurable: true,
77
- value: 600,
92
+ mockScrollableElement(scroll, {
93
+ clientWidth: 200,
94
+ scrollWidth: 600,
78
95
  });
79
96
 
80
97
  scroll.scrollLeft = 120;
@@ -134,13 +151,9 @@ describe("Datatable drag scroll", function () {
134
151
  expect(scroll).to.exist;
135
152
  expect(button).to.exist;
136
153
 
137
- Object.defineProperty(scroll, "clientWidth", {
138
- configurable: true,
139
- value: 200,
140
- });
141
- Object.defineProperty(scroll, "scrollWidth", {
142
- configurable: true,
143
- value: 600,
154
+ mockScrollableElement(scroll, {
155
+ clientWidth: 200,
156
+ scrollWidth: 600,
144
157
  });
145
158
 
146
159
  scroll.scrollLeft = 120;
@@ -255,4 +268,195 @@ describe("Datatable drag scroll", function () {
255
268
  await new Promise((resolve) => setTimeout(resolve, 0));
256
269
  expect(copied).deep.equal(['"Alpha";"Beta"']);
257
270
  });
271
+
272
+ it("defers resize observer grid updates to the next animation frame", async function () {
273
+ const OriginalResizeObserver = window.ResizeObserver;
274
+ const originalGlobalResizeObserver = globalThis.ResizeObserver;
275
+ const originalRequestAnimationFrame = window.requestAnimationFrame;
276
+ const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;
277
+
278
+ class TrackingResizeObserver extends ResizeObserverMock {
279
+ static instances = [];
280
+
281
+ constructor(callback) {
282
+ super(callback);
283
+ TrackingResizeObserver.instances.push(this);
284
+ }
285
+ }
286
+
287
+ try {
288
+ window.ResizeObserver = TrackingResizeObserver;
289
+ globalThis.ResizeObserver = TrackingResizeObserver;
290
+
291
+ const mocks = document.getElementById("mocks");
292
+ const wrapper = document.createElement("div");
293
+ let wrapperWidth = 500;
294
+
295
+ Object.defineProperty(wrapper, "clientWidth", {
296
+ configurable: true,
297
+ get: () => wrapperWidth,
298
+ });
299
+
300
+ mocks.appendChild(wrapper);
301
+
302
+ const datatable = document.createElement("monster-datatable");
303
+ datatable.id = "resize-scheduled-table";
304
+ datatable.innerHTML = `
305
+ <template id="resize-scheduled-table-row">
306
+ <div data-monster-head="Name">Alpha</div>
307
+ <div data-monster-head="Value">Beta</div>
308
+ </template>
309
+ `;
310
+ datatable.setOption("responsive.breakpoint", 300);
311
+ datatable.setOption("data", [{}]);
312
+ wrapper.appendChild(datatable);
313
+
314
+ await new Promise((resolve) => setTimeout(resolve, 30));
315
+
316
+ const control = datatable.shadowRoot.querySelector(
317
+ "[data-monster-role=control]",
318
+ );
319
+ expect(control).to.exist;
320
+ expect(control.classList.contains("small")).to.equal(false);
321
+ expect(TrackingResizeObserver.instances).to.have.length.greaterThan(0);
322
+ const tableResizeObserver = TrackingResizeObserver.instances.find(
323
+ (observer) => observer.elements.includes(wrapper),
324
+ );
325
+ expect(tableResizeObserver).to.exist;
326
+
327
+ let scheduledCallback = null;
328
+ window.requestAnimationFrame = (callback) => {
329
+ scheduledCallback = callback;
330
+ return 1;
331
+ };
332
+ globalThis.requestAnimationFrame = window.requestAnimationFrame;
333
+
334
+ wrapperWidth = 200;
335
+ tableResizeObserver.triggerResize([]);
336
+
337
+ expect(scheduledCallback).to.be.a("function");
338
+ expect(control.classList.contains("small")).to.equal(false);
339
+
340
+ scheduledCallback();
341
+
342
+ expect(control.classList.contains("small")).to.equal(true);
343
+ } finally {
344
+ window.ResizeObserver = OriginalResizeObserver;
345
+ globalThis.ResizeObserver = originalGlobalResizeObserver;
346
+ window.requestAnimationFrame = originalRequestAnimationFrame;
347
+ globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
348
+ }
349
+ });
350
+
351
+ it("defers column bar resize updates to the next animation frame", async function () {
352
+ const OriginalResizeObserver = window.ResizeObserver;
353
+ const originalGlobalResizeObserver = globalThis.ResizeObserver;
354
+ const originalRequestAnimationFrame = window.requestAnimationFrame;
355
+ const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;
356
+
357
+ class TrackingResizeObserver extends ResizeObserverMock {
358
+ static instances = [];
359
+
360
+ constructor(callback) {
361
+ super(callback);
362
+ TrackingResizeObserver.instances.push(this);
363
+ }
364
+ }
365
+
366
+ try {
367
+ window.ResizeObserver = TrackingResizeObserver;
368
+ globalThis.ResizeObserver = TrackingResizeObserver;
369
+
370
+ const mocks = document.getElementById("mocks");
371
+ const wrapper = document.createElement("div");
372
+ let parentWidth = 400;
373
+
374
+ Object.defineProperty(wrapper, "getBoundingClientRect", {
375
+ configurable: true,
376
+ value: () => ({ width: parentWidth }),
377
+ });
378
+
379
+ mocks.appendChild(wrapper);
380
+
381
+ const columnBar = document.createElement("monster-column-bar");
382
+ columnBar.setOption("columns", [
383
+ { index: 0, name: "One", visible: true },
384
+ { index: 1, name: "Two", visible: true },
385
+ { index: 2, name: "Three", visible: true },
386
+ { index: 3, name: "Four", visible: true },
387
+ { index: 4, name: "Five", visible: true },
388
+ { index: 5, name: "Six", visible: true },
389
+ ]);
390
+ wrapper.appendChild(columnBar);
391
+
392
+ await new Promise((resolve) => setTimeout(resolve, 30));
393
+
394
+ const control = columnBar.shadowRoot.querySelector(
395
+ "[data-monster-role=control]",
396
+ );
397
+ const settingsButton = columnBar.shadowRoot.querySelector(
398
+ "[data-monster-role=settings-button]",
399
+ );
400
+ const dotsContainer = columnBar.shadowRoot.querySelector(
401
+ "[data-monster-role=dots]",
402
+ );
403
+ const dots = Array.from(dotsContainer.querySelectorAll("li"));
404
+
405
+ expect(control).to.exist;
406
+ expect(settingsButton).to.exist;
407
+ expect(dots.length).to.equal(6);
408
+
409
+ Object.defineProperty(control, "getBoundingClientRect", {
410
+ configurable: true,
411
+ value: () => ({ width: parentWidth }),
412
+ });
413
+ Object.defineProperty(settingsButton, "getBoundingClientRect", {
414
+ configurable: true,
415
+ value: () => ({ width: 20 }),
416
+ });
417
+ dots.forEach((dot) => {
418
+ Object.defineProperty(dot, "getBoundingClientRect", {
419
+ configurable: true,
420
+ value: () => ({ width: 20 }),
421
+ });
422
+ });
423
+
424
+ await new Promise((resolve) => setTimeout(resolve, 0));
425
+
426
+ expect(
427
+ dotsContainer.querySelector(".dots-overflow-indicator"),
428
+ ).to.equal(null);
429
+
430
+ const columnBarResizeObserver = TrackingResizeObserver.instances.find(
431
+ (observer) => observer.elements.includes(control),
432
+ );
433
+ expect(columnBarResizeObserver).to.exist;
434
+
435
+ let scheduledCallback = null;
436
+ window.requestAnimationFrame = (callback) => {
437
+ scheduledCallback = callback;
438
+ return 1;
439
+ };
440
+ globalThis.requestAnimationFrame = window.requestAnimationFrame;
441
+
442
+ parentWidth = 80;
443
+ columnBarResizeObserver.triggerResize([]);
444
+
445
+ expect(scheduledCallback).to.be.a("function");
446
+ expect(
447
+ dotsContainer.querySelector(".dots-overflow-indicator"),
448
+ ).to.equal(null);
449
+
450
+ scheduledCallback();
451
+
452
+ expect(
453
+ dotsContainer.querySelector(".dots-overflow-indicator"),
454
+ ).to.exist;
455
+ } finally {
456
+ window.ResizeObserver = OriginalResizeObserver;
457
+ globalThis.ResizeObserver = originalGlobalResizeObserver;
458
+ window.requestAnimationFrame = originalRequestAnimationFrame;
459
+ globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
460
+ }
461
+ });
258
462
  });
@@ -0,0 +1,168 @@
1
+ import * as chai from "chai";
2
+ import { chaiDom } from "../../../util/chai-dom.mjs";
3
+ import { initJSDOM } from "../../../util/jsdom.mjs";
4
+
5
+ let expect = chai.expect;
6
+ chai.use(chaiDom);
7
+
8
+ let Login;
9
+
10
+ describe("Login", function () {
11
+ before(function (done) {
12
+ initJSDOM().then(() => {
13
+ import("element-internals-polyfill")
14
+ .then(() => import("../../../../source/components/form/login.mjs"))
15
+ .then((module) => {
16
+ Login = module.Login;
17
+ done();
18
+ })
19
+ .catch((error) => done(error));
20
+ });
21
+ });
22
+
23
+ beforeEach(() => {
24
+ document.getElementById("mocks").innerHTML = "";
25
+ });
26
+
27
+ afterEach(() => {
28
+ document.getElementById("mocks").innerHTML = "";
29
+ });
30
+
31
+ it("should create a monster-login element", function () {
32
+ expect(document.createElement("monster-login")).is.instanceof(Login);
33
+ });
34
+
35
+ it("should respect the native hidden attribute on the host", function (done) {
36
+ const login = document.createElement("monster-login");
37
+ login.setAttribute("hidden", "");
38
+ document.getElementById("mocks").appendChild(login);
39
+
40
+ setTimeout(() => {
41
+ try {
42
+ expect(login.hidden).to.be.true;
43
+ expect(login.visible).to.be.false;
44
+ expect(login.isVisible).to.be.false;
45
+ done();
46
+ } catch (error) {
47
+ done(error);
48
+ }
49
+ }, 100);
50
+ });
51
+
52
+ it("should hide and show the host with the public visibility API", function (done) {
53
+ const login = document.createElement("monster-login");
54
+ document.getElementById("mocks").appendChild(login);
55
+
56
+ const states = [];
57
+ login.addEventListener("monster-visibility-changed", (event) => {
58
+ states.push(event.detail.visible);
59
+ });
60
+
61
+ setTimeout(() => {
62
+ try {
63
+ const username = login.shadowRoot.querySelector("input[name='username']");
64
+ username.focus();
65
+
66
+ login.hide();
67
+ } catch (error) {
68
+ done(error);
69
+ }
70
+ }, 150);
71
+
72
+ setTimeout(() => {
73
+ try {
74
+ expect(login.hidden).to.be.true;
75
+ expect(login.visible).to.be.false;
76
+
77
+ login.show();
78
+
79
+ setTimeout(() => {
80
+ try {
81
+ expect(login.hidden).to.be.false;
82
+ expect(login.visible).to.be.true;
83
+ expect(states).to.deep.equal([false, true]);
84
+ done();
85
+ } catch (error) {
86
+ done(error);
87
+ }
88
+ }, 25);
89
+ } catch (error) {
90
+ done(error);
91
+ }
92
+ }, 200);
93
+ });
94
+
95
+ it("should keep host visibility separate from openLogin", function (done) {
96
+ const login = document.createElement("monster-login");
97
+ document.getElementById("mocks").appendChild(login);
98
+
99
+ setTimeout(() => {
100
+ try {
101
+ login.hide();
102
+ login.openLogin();
103
+
104
+ expect(login.hidden).to.be.true;
105
+ expect(login.visible).to.be.false;
106
+ done();
107
+ } catch (error) {
108
+ done(error);
109
+ }
110
+ }, 150);
111
+ });
112
+
113
+ it("should show the custom collapse and close the login collapse", function (done) {
114
+ const login = document.createElement("monster-login");
115
+ document.getElementById("mocks").appendChild(login);
116
+
117
+ setTimeout(() => {
118
+ try {
119
+ const loginCollapse = login.shadowRoot.querySelector(
120
+ '[data-monster-role="login-collapse"]',
121
+ );
122
+ const customCollapse = login.shadowRoot.querySelector(
123
+ '[data-monster-role="custom-collapse"]',
124
+ );
125
+
126
+ expect(loginCollapse.isOpen()).to.be.true;
127
+ expect(customCollapse.isClosed()).to.be.true;
128
+
129
+ const button = document.createElement("button");
130
+ button.textContent = "Weiter";
131
+
132
+ login.showCustomCollapse({
133
+ header: "Hinweis",
134
+ content: ["Manueller Inhalt", button],
135
+ footer: "Footer",
136
+ });
137
+
138
+ setTimeout(() => {
139
+ try {
140
+ expect(customCollapse.isOpen()).to.be.true;
141
+ expect(loginCollapse.isClosed()).to.be.true;
142
+ expect(
143
+ login.shadowRoot.getElementById("customCollapseHeader").textContent,
144
+ ).to.equal("Hinweis");
145
+ expect(
146
+ login.shadowRoot
147
+ .getElementById("customCollapseContent")
148
+ .textContent.includes("Manueller Inhalt"),
149
+ ).to.be.true;
150
+ expect(
151
+ login.shadowRoot
152
+ .getElementById("customCollapseContent")
153
+ .querySelector("button"),
154
+ ).to.equal(button);
155
+ expect(
156
+ login.shadowRoot.getElementById("customCollapseFooter").textContent,
157
+ ).to.equal("Footer");
158
+ done();
159
+ } catch (error) {
160
+ done(error);
161
+ }
162
+ }, 700);
163
+ } catch (error) {
164
+ done(error);
165
+ }
166
+ }, 150);
167
+ });
168
+ });
@@ -238,7 +238,7 @@ describe('Select', function () {
238
238
  });
239
239
 
240
240
  it('should reset pagination and clear options on fetch error', function (done) {
241
- this.timeout(4000);
241
+ this.timeout(5000);
242
242
 
243
243
  let mocks = document.getElementById('mocks');
244
244
  const select = document.createElement('monster-select');
@@ -257,47 +257,85 @@ describe('Select', function () {
257
257
  const triggerFilter = (value) => {
258
258
  const filterInput = select.shadowRoot.querySelector('[data-monster-role=filter]');
259
259
  filterInput.value = value;
260
+ filterInput.dispatchEvent(new InputEvent('input', {
261
+ bubbles: true,
262
+ composed: true,
263
+ data: value
264
+ }));
260
265
  filterInput.dispatchEvent(new KeyboardEvent('keydown', {
261
266
  code: 'KeyA',
262
- bubbles: true
267
+ key: 'a',
268
+ bubbles: true,
269
+ composed: true
263
270
  }));
264
271
  };
265
272
 
266
- select.addEventListener('monster-options-set', () => {
267
- setTimeout(() => {
268
- try {
269
- const options = select.getOption('options');
270
- expect(options.length).to.equal(1);
271
- expect(pagination().getOption('currentPage')).to.equal(1);
272
- expect(pagination().getOption('pages')).to.equal(2);
273
- expect(pagination().getOption('objectsPerPage')).to.equal(1);
274
-
275
- triggerFilter('b');
276
-
277
- setTimeout(() => {
278
- try {
279
- const optionsAfterError = select.getOption('options');
280
- expect(optionsAfterError.length).to.equal(0);
281
- expect(pagination().getOption('currentPage')).to.equal(null);
282
- expect(pagination().getOption('pages')).to.equal(null);
283
- expect(pagination().getOption('objectsPerPage')).to.equal(null);
284
- expect(select.getOption('total')).to.equal(null);
285
- expect(select.getOption('messages.total')).to.equal("");
286
- } catch (e) {
287
- return done(e);
288
- }
273
+ const startedAt = Date.now();
274
+ const pollLoadedState = () => {
275
+ try {
276
+ const options = select.getOption('options');
277
+ const pager = pagination();
278
+
279
+ if (
280
+ options?.length !== 1 ||
281
+ !pager ||
282
+ pager.getOption('currentPage') !== 1 ||
283
+ pager.getOption('pages') !== 2 ||
284
+ pager.getOption('objectsPerPage') !== 1
285
+ ) {
286
+ if (Date.now() - startedAt < 3000) {
287
+ return setTimeout(pollLoadedState, 50);
288
+ }
289
+ }
289
290
 
290
- done();
291
- }, 500);
292
- } catch (e) {
293
- done(e);
291
+ expect(options.length).to.equal(1);
292
+ expect(pager.getOption('currentPage')).to.equal(1);
293
+ expect(pager.getOption('pages')).to.equal(2);
294
+ expect(pager.getOption('objectsPerPage')).to.equal(1);
295
+
296
+ triggerFilter('b');
297
+ setTimeout(pollErrorState, 50);
298
+ } catch (e) {
299
+ done(e);
300
+ }
301
+ };
302
+
303
+ const pollErrorState = () => {
304
+ try {
305
+ const optionsAfterError = select.getOption('options');
306
+ const pager = pagination();
307
+
308
+ if (
309
+ optionsAfterError?.length !== 0 ||
310
+ !pager ||
311
+ pager.getOption('currentPage') !== null ||
312
+ pager.getOption('pages') !== null ||
313
+ pager.getOption('objectsPerPage') !== null ||
314
+ select.getOption('total') !== null ||
315
+ select.getOption('messages.total') !== ""
316
+ ) {
317
+ if (Date.now() - startedAt < 4500) {
318
+ return setTimeout(pollErrorState, 50);
319
+ }
294
320
  }
295
- }, 50);
296
- }, {once: true});
321
+
322
+ expect(optionsAfterError.length).to.equal(0);
323
+ expect(pager.getOption('currentPage')).to.equal(null);
324
+ expect(pager.getOption('pages')).to.equal(null);
325
+ expect(pager.getOption('objectsPerPage')).to.equal(null);
326
+ expect(select.getOption('total')).to.equal(null);
327
+ expect(select.getOption('messages.total')).to.equal("");
328
+ } catch (e) {
329
+ return done(e);
330
+ }
331
+
332
+ done();
333
+ };
297
334
 
298
335
  setTimeout(() => {
299
336
  triggerFilter('a');
300
- }, 0);
337
+ setTimeout(pollLoadedState, 50);
338
+ }, 50);
301
339
  });
302
340
  });
303
341
 
@@ -333,6 +371,30 @@ describe('Select', function () {
333
371
 
334
372
  });
335
373
 
374
+ it('should expose styling parts for container, filter messages and pagination', function (done) {
375
+
376
+ let mocks = document.getElementById('mocks');
377
+ const select = document.createElement('monster-select');
378
+ select.setOption('filter.mode', 'remote');
379
+ mocks.appendChild(select);
380
+
381
+ setTimeout(() => {
382
+ try {
383
+ const container = select.shadowRoot.querySelector('[data-monster-role=container]');
384
+ const selectionMessages = select.shadowRoot.querySelector('[data-monster-role=selection-messages]');
385
+ const pagination = select.shadowRoot.querySelector('[data-monster-role=pagination]');
386
+
387
+ expect(container.getAttribute('part')).to.equal('container');
388
+ expect(selectionMessages.getAttribute('part')).to.equal('selection-messages');
389
+ expect(pagination.getAttribute('part')).to.equal('pagination');
390
+ } catch (e) {
391
+ return done(e);
392
+ }
393
+
394
+ done();
395
+ }, 0)
396
+ });
397
+
336
398
  it('should normalize options without throwing', function (done) {
337
399
  this.timeout(2000);
338
400
 
@@ -212,7 +212,28 @@ describe('Treeselect', function () {
212
212
 
213
213
  });
214
214
 
215
+ it('should expose styling parts for container and popper filter control', function (done) {
216
+
217
+ let mocks = document.getElementById('mocks');
218
+ const select = document.createElement('monster-tree-select');
219
+ mocks.appendChild(select);
220
+
221
+ setTimeout(() => {
222
+ try {
223
+ const container = select.shadowRoot.querySelector('[data-monster-role=container]');
224
+ const popperFilterControl = select.shadowRoot.querySelector('.option-filter-control');
225
+
226
+ expect(container.getAttribute('part')).to.equal('container');
227
+ expect(popperFilterControl.getAttribute('part')).to.equal('popper-filter-control');
228
+ } catch (e) {
229
+ return done(e);
230
+ }
231
+
232
+ done();
233
+ }, 0)
234
+ });
235
+
215
236
  });
216
237
 
217
238
 
218
- });
239
+ });
@@ -161,9 +161,9 @@ describe('DOM', function () {
161
161
  //
162
162
  // })
163
163
 
164
- describe('Test ElementInternals', function () {
164
+ describe('Test ElementInternals', function () {
165
165
 
166
- let form;
166
+ let form;
167
167
 
168
168
  beforeEach(() => {
169
169
  form = document.createElement('form');
@@ -276,18 +276,52 @@ describe('DOM', function () {
276
276
  });
277
277
 
278
278
 
279
- it('setValidity()', function () {
279
+ it('setValidity()', function () {
280
280
 
281
- let d = document.createElement('monster-customcontrol');
282
- form.appendChild(d);
283
- expect(d.setValidity({'valueMissing': true}, "my message")).to.be.undefined;
281
+ let d = document.createElement('monster-customcontrol');
282
+ form.appendChild(d);
283
+ expect(d.setValidity({'valueMissing': true}, "my message")).to.be.undefined;
284
284
 
285
- });
285
+ });
286
286
 
287
+ it('formResetCallback() should restore the value attribute', function () {
288
+ const htmlTAG = 'monster-customcontrol-reset';
287
289
 
288
- });
289
- });
290
+ class ResetComponent extends CustomControl {
291
+ static getTag() {
292
+ return htmlTAG;
293
+ }
290
294
 
291
- });
295
+ get defaults() {
296
+ return Object.assign({}, super.defaults, {
297
+ shadowMode: false,
298
+ });
299
+ }
300
+
301
+ get value() {
302
+ return this._value ?? '';
303
+ }
304
+
305
+ set value(value) {
306
+ this._value = value;
307
+ }
308
+ }
292
309
 
310
+ registerCustomElement(ResetComponent);
311
+
312
+ let d = document.createElement(htmlTAG);
313
+ d.setAttribute('value', 'seed');
314
+ d.value = 'changed';
315
+ form.appendChild(d);
316
+
317
+ d.formResetCallback();
318
+
319
+ expect(d.value).to.equal('seed');
320
+ });
321
+
322
+
323
+ });
324
+ });
325
+
326
+ });
293
327