@schukai/monster 4.38.3 → 4.38.5

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.
@@ -1,12 +1,12 @@
1
- 'use strict';
1
+ "use strict";
2
2
 
3
- import * as chai from 'chai';
3
+ import * as chai from "chai";
4
4
 
5
- import {ID} from "../../../source/types/id.mjs";
6
- import {Observer} from "../../../source/types/observer.mjs";
7
- import {ProxyObserver} from "../../../source/types/proxyobserver.mjs";
8
- import {chaiDom} from "../../util/chai-dom.mjs";
9
- import {initJSDOM} from "../../util/jsdom.mjs";
5
+ import { ID } from "../../../source/types/id.mjs";
6
+ import { Observer } from "../../../source/types/observer.mjs";
7
+ import { ProxyObserver } from "../../../source/types/proxyobserver.mjs";
8
+ import { chaiDom } from "../../util/chai-dom.mjs";
9
+ import { initJSDOM } from "../../util/jsdom.mjs";
10
10
 
11
11
  let expect = chai.expect;
12
12
 
@@ -109,624 +109,645 @@ let html4 = `
109
109
 
110
110
  `;
111
111
 
112
+ describe("DOM", function () {
113
+ let Updater = null;
112
114
 
113
-
114
- describe('DOM', function () {
115
-
116
- let Updater = null;
117
-
118
- before(function (done) {
119
- const options = {
120
- }
121
- initJSDOM(options).then(() => {
122
-
123
- import("../../../source/dom/updater.mjs").then((m) => {
124
- Updater = m.Updater;
125
- done();
126
- }).catch((e) => {
127
- done(e)
128
- });
115
+ before(function (done) {
116
+ const options = {};
117
+ initJSDOM(options).then(() => {
118
+ import("../../../source/dom/updater.mjs")
119
+ .then((m) => {
120
+ Updater = m.Updater;
121
+ done();
122
+ })
123
+ .catch((e) => {
124
+ done(e);
129
125
  });
130
126
  });
127
+ });
131
128
 
132
- beforeEach(() => {
133
- let mocks = document.getElementById('mocks');
134
- mocks.innerHTML = html1;
135
- })
136
-
137
- afterEach(() => {
138
- let mocks = document.getElementById('mocks');
139
- mocks.innerHTML = "";
140
- })
141
-
142
- describe('Updater()', function () {
143
- describe('test Getter && Setter', function () {
144
- it('setEventTypes()', function () {
145
- let element = document.getElementById('test1')
146
- expect(new Updater(element).setEventTypes(['touch'])).to.be.instanceof(Updater);
147
- })
148
- it('getSubject()', function () {
149
- let element = document.getElementById('test1')
150
- let subject = {a: 1};
151
- expect(new Updater(element, subject).getSubject().a).to.be.equal(1);
152
- })
153
- });
154
-
155
- describe('test control methods', function () {
156
- it('enableEventProcessing()', function () {
157
- let element = document.getElementById('test1')
158
- expect(new Updater(element).enableEventProcessing()).to.be.instanceof(Updater);
159
- })
160
-
161
- it('disableEventProcessing()', function () {
162
- let element = document.getElementById('test1')
163
- expect(new Updater(element).disableEventProcessing()).to.be.instanceof(Updater);
164
- })
165
- });
166
-
167
- describe('test Errors', function () {
168
-
169
- it('should throw value is not an instance of HTMLElement Error', function () {
170
- expect(() => new Updater()).to.throw(TypeError)
171
- })
172
-
173
- it('should throw value is wrong', function () {
174
-
175
- let element = document.getElementById('test1')
176
- expect(() => new Updater(element, null)).to.throw(TypeError)
177
- })
178
-
179
- it('should throw Error: the value is not iterable', function (done) {
180
- let element = document.getElementById('test1')
181
-
182
- let u = new Updater(
183
- element,
184
- {
185
- a: {
186
- x: []
187
- }
188
- }
189
- );
190
-
191
- let promise = u.run();
129
+ beforeEach(() => {
130
+ let mocks = document.getElementById("mocks");
131
+ mocks.innerHTML = html1;
132
+ });
192
133
 
193
- setTimeout(() => {
194
- promise.then(() => {
195
- setTimeout(() => {
196
- done(new Error("should never called!"));
197
- }, 100);
198
- }).catch((e) => {
199
- expect(e).is.instanceOf(Error);
200
- expect(e + "").to.be.equal('Error: the value is not iterable');
201
- done();
202
- })
203
- }, 100);
204
-
205
- });
134
+ afterEach(() => {
135
+ let mocks = document.getElementById("mocks");
136
+ mocks.innerHTML = "";
137
+ });
206
138
 
139
+ // REFACTOR: Ein einziger, klar benannter describe-Block für zusammengehörige Tests.
140
+ describe("Setup, Configuration, and Error Handling", function () {
141
+ let element;
207
142
 
208
- });
143
+ // REFACTOR: Code-Wiederholung durch einen beforeEach-Hook vermeiden.
144
+ beforeEach(() => {
145
+ // Annahme: Die HTML-Struktur aus der vorherigen Anfrage ist im DOM vorhanden.
146
+ // Falls nicht, müsste hier das entsprechende HTML geladen werden.
147
+ element = document.getElementById("test1");
209
148
  });
210
149
 
211
- describe('Updater()', function () {
212
- describe('new Updater', function () {
213
-
214
- it('should return document object', function () {
215
- let element = document.getElementById('test1')
216
-
217
- let d = new Updater(
218
- element,
219
- {}
220
- );
221
-
222
- expect(typeof d).is.equal('object');
223
- });
224
- });
150
+ describe("Configuration Methods", function () {
151
+ it("setEventTypes() should be chainable", function () {
152
+ const u = new Updater(element);
153
+ expect(u.setEventTypes(["touch"])).to.be.instanceof(Updater);
154
+ });
155
+
156
+ it("getSubject() should return the subject proxy", function () {
157
+ const subject = { a: 1 };
158
+ const u = new Updater(element, subject);
159
+ expect(u.getSubject().a).to.be.equal(1);
160
+ });
161
+
162
+ it("enableEventProcessing() should be chainable", function () {
163
+ const u = new Updater(element);
164
+ expect(u.enableEventProcessing()).to.be.instanceof(Updater);
165
+ });
166
+
167
+ it("disableEventProcessing() should be chainable", function () {
168
+ const u = new Updater(element);
169
+ expect(u.disableEventProcessing()).to.be.instanceof(Updater);
170
+ });
225
171
  });
226
172
 
227
- describe('Updater()', function () {
228
- describe('Repeat', function () {
229
-
230
- it('should build 6 li elements', function (done) {
231
- let element = document.getElementById('test1')
232
-
233
- let d = new Updater(
234
- element,
235
- {
236
- a: {
237
- b: [
238
- {i: '0'},
239
- {i: '1'},
240
- {i: '2'},
241
- {i: '3'},
242
- {i: '4'},
243
- {i: '5'},
244
- ]
245
- }
246
- }
247
- );
248
-
249
- d.run().then(() => {
250
- setTimeout(() => {
251
- expect(typeof d).is.equal('object');
252
- for (let i = 0; i < 6; i++) {
253
- expect(element).contain.html('<li data-monster-replace="path:a.b.' + i + ' | tojson" data-monster-insert-reference="current-' + i + '">{"i":"' + i + '"}</li>');
254
- }
255
-
256
- done();
257
- }, 100);
173
+ describe("Constructor Error Handling", function () {
174
+ it("should throw a TypeError if no HTMLElement is provided", function () {
175
+ expect(() => new Updater()).to.throw(TypeError);
176
+ });
258
177
 
259
- }).catch(
260
- e => {
261
- done(new Error(e))
262
- })
263
-
264
-
265
- });
266
-
267
- });
178
+ it("should throw a TypeError if the subject is not an object", function () {
179
+ expect(() => new Updater(element, null)).to.throw(TypeError);
180
+ });
268
181
  });
182
+ describe("Setup, Configuration, and Error Handling", function () {
183
+ let element;
269
184
 
270
- describe('Updater()', function () {
271
-
272
- beforeEach(() => {
273
- let mocks = document.getElementById('mocks');
274
- mocks.innerHTML = html4;
275
- })
276
-
277
- describe('Eventhandling', function () {
278
-
279
- let updater, form1, proxyobserver;
280
- beforeEach(() => {
281
- proxyobserver = new ProxyObserver({})
282
- updater = new Updater(document.getElementById('form1'), proxyobserver);
283
- form1 = document.getElementById('form1');
284
-
285
- })
286
-
287
- // here click events are thrown on the checkbox and the setting of the value is observed via the proxyobserver.
288
- it('should handle checkbox click events', function (done) {
289
-
290
- updater.enableEventProcessing();
291
-
292
- let subject = updater.getSubject();
293
- expect(subject).is.equal(proxyobserver.getSubject());
294
-
295
- let expected = ['checked', undefined, 'checked'];
296
- // here the notation with function is important, because the pointer is set.
297
- proxyobserver.attachObserver(new Observer(function () {
298
-
299
- let e = expected.shift();
300
- if (e === undefined && expected.length === 0) done(new Error('to many calls'));
301
-
302
- if (this.getSubject()['state'] !== e) done(new Error(this.getSubject()['state'] + ' should ' + e));
303
- if (expected.length === 0) {
304
- done();
305
- } else {
306
-
307
- setTimeout(() => {
308
- form1.querySelector('[name=checkbox]').click();
309
- }, 10)
310
-
311
- }
312
- }));
313
-
314
- setTimeout(() => {
315
- form1.querySelector('[name=checkbox]').click();
316
- }, 10)
317
-
318
-
319
- })
320
-
321
- it('should handle radio click events 1', function (done) {
322
-
323
- updater.enableEventProcessing();
324
-
325
- let subject = updater.getSubject();
326
- expect(subject).is.equal(proxyobserver.getSubject());
327
-
328
- let expected = ['r1', 'r2', 'r1'];
329
- let clickTargets = ['r2', 'r1']
330
- // here the notation with function is important, because the this pointer is set.
331
- proxyobserver.attachObserver(new Observer(function () {
332
-
333
- let e = expected.shift();
334
- if (e === undefined && expected.length === 0) done(new Error('to many calls'));
335
-
336
- let v = this.getSubject()['radio'];
337
- if (v !== e) done(new Error(v + ' should ' + e));
338
- if (expected.length === 0) {
339
- done();
340
- } else {
341
- setTimeout(() => {
342
- document.getElementById(clickTargets.shift()).click();
343
- }, 10)
344
-
345
- }
346
- }));
347
-
348
- setTimeout(() => {
349
- document.getElementById('r1').click();
350
- }, 10)
351
-
352
- // no handler // bind
353
- setTimeout(() => {
354
- document.getElementById('rx').click();
355
- }, 20)
356
-
357
- })
358
-
359
- it('should handle select click events 2', function (done) {
360
-
361
- let selectElement = document.getElementById('select1');
362
-
363
- updater.enableEventProcessing();
364
-
365
- let subject = updater.getSubject();
366
- expect(subject).is.equal(proxyobserver.getSubject());
367
-
368
- let expected = ['value2', 'value1', 'value2'];
369
- // here the notation with function is important, because the this pointer is set.
370
- proxyobserver.attachObserver(new Observer(function () {
371
-
372
- let e = expected.shift();
373
- if (e === undefined && expected.length === 0) done(new Error('to many calls'));
374
-
375
- let v = this.getSubject()['select'];
376
- if (v !== e) done(new Error(v + ' should ' + e));
377
- if (expected.length === 0) {
378
- done();
379
- } else {
380
- setTimeout(() => {
381
- selectElement.selectedIndex = selectElement.selectedIndex === 1 ? 0 : 1;
382
- selectElement.click();
383
- }, 10)
384
-
385
- }
386
- }));
387
-
388
- setTimeout(() => {
389
- // set value and simulate click event for bubble
390
- selectElement.selectedIndex = 1;
391
- selectElement.click();
392
-
393
- }, 20)
394
-
395
- });
396
-
397
- it('should handle textarea events', function (done) {
398
-
399
- let textareaElement = document.getElementById('textarea');
400
-
401
- updater.enableEventProcessing();
402
-
403
- let subject = updater.getSubject();
404
- expect(subject).is.equal(proxyobserver.getSubject());
405
-
406
- let expected = ['testX', 'lorem ipsum', ''];
407
- let testValues = ["lorem ipsum", ""];
408
- // here the notation with function is important, because the this pointer is set.
409
- proxyobserver.attachObserver(new Observer(function () {
410
-
411
- let e = expected.shift();
412
- if (e === undefined && expected.length === 0) done(new Error('to many calls'));
413
-
414
- let v = this.getSubject()['textarea'];
415
- if (JSON.stringify(v) !== JSON.stringify(e)) done(new Error(JSON.stringify(v) + ' should ' + JSON.stringify(e)));
416
- if (expected.length === 0) {
417
- done();
418
- } else {
419
- setTimeout(() => {
420
- textareaElement.value = testValues.shift();
421
- textareaElement.click();
422
- }, 10)
423
-
424
- }
425
- }));
426
-
427
- setTimeout(() => {
428
-
429
- // set value and simulate click event for bubble
430
- textareaElement.value = "testX";
431
- textareaElement.click();
432
-
433
- }, 20)
434
-
435
- });
436
-
437
- it('should handle multiple select events', function (done) {
438
-
439
- let selectElement = document.getElementById('select2');
440
-
441
- updater.enableEventProcessing();
442
-
443
- let subject = updater.getSubject();
444
- expect(subject).is.equal(proxyobserver.getSubject());
445
-
446
- let expected = [
447
- ['value1'],
448
- ['value2', 'value3', 'value4'],
449
- ['value1', 'value4'],
450
- ];
185
+ beforeEach(() => {
186
+ element = document.getElementById("test1");
187
+ });
451
188
 
452
- let testSelections = [
453
- [false, true, true, true],
454
- [true, false, false, true],
455
- ]
456
-
457
- // here the notation with function is important, because the this pointer is set.
458
- proxyobserver.attachObserver(new Observer(function () {
459
-
460
- let e = expected.shift();
461
- if (e === undefined && expected.length === 0) done(new Error('to many calls'));
462
-
463
- let v = this.getSubject()['multiselect'];
464
-
465
- if (JSON.stringify(v) !== JSON.stringify(e)) done(new Error(JSON.stringify(v) + ' should ' + JSON.stringify(e)));
466
- if (expected.length === 0) {
467
- done();
468
- } else {
469
- setTimeout(() => {
470
- let v = testSelections.shift();
471
- selectElement.options[0].selected = v[0];
472
- selectElement.options[1].selected = v[1];
473
- selectElement.options[2].selected = v[2];
474
- selectElement.options[3].selected = v[3];
475
- selectElement.click();
476
- }, 10)
477
-
478
- }
479
- }));
480
-
481
- setTimeout(() => {
482
-
483
- selectElement.options[0].selected = true;
484
- selectElement.options[1].selected = false;
485
- selectElement.options[2].selected = false;
486
- selectElement.options[3].selected = false;
487
- selectElement.click();
488
-
489
- }, 20)
490
-
491
-
492
- });
189
+ describe("Configuration Methods", function () {
190
+ it("setEventTypes() should be chainable", function () {
191
+ const u = new Updater(element);
192
+ expect(u.setEventTypes(["touch"])).to.be.instanceof(Updater);
493
193
  });
494
194
 
495
- })
496
-
497
-
498
- describe('Updater()', function () {
499
-
500
- beforeEach(() => {
501
- let mocks = document.getElementById('mocks');
502
- mocks.innerHTML = html2;
503
- })
504
-
505
- describe('Replace', function () {
506
-
507
- it('should add lower hello and HELLOyes!', function (done) {
508
- let element = document.getElementById('test1')
509
-
510
-
511
- let d = new Updater(
512
- element,
513
- {
514
- text: "HALLO"
515
- }
516
- );
517
-
518
-
519
- d.setCallback('myformatter', function (a) {
520
- return a + 'yes!'
521
- })
522
-
523
-
524
- d.run().then(() => {
525
- setTimeout(() => {
526
- expect(typeof d).is.equal('object');
527
- expect(element).contain.html('<div data-monster-replace="path:text | tolower">hallo</div>');
528
- expect(element).contain.html('<div data-monster-replace="path:text | call:myformatter">HALLOyes!</div>');
529
- expect(element).contain.html('<div data-monster-replace="static:hello\\ ">hello </div>');
530
-
531
- return done();
195
+ it("getSubject() should return the subject proxy", function () {
196
+ const subject = { a: 1 };
197
+ const u = new Updater(element, subject);
198
+ expect(u.getSubject().a).to.be.equal(1);
199
+ });
532
200
 
533
- }, 100);
201
+ it("enableEventProcessing() should be chainable", function () {
202
+ const u = new Updater(element);
203
+ expect(u.enableEventProcessing()).to.be.instanceof(Updater);
204
+ });
534
205
 
535
- }).catch(
536
- e => {
537
- done(new Error(e))
538
- })
206
+ it("disableEventProcessing() should be chainable", function () {
207
+ const u = new Updater(element);
208
+ expect(u.disableEventProcessing()).to.be.instanceof(Updater);
209
+ });
210
+ });
539
211
 
212
+ describe("Constructor Error Handling", function () {
213
+ it("should throw a TypeError if no HTMLElement is provided", function () {
214
+ expect(() => new Updater()).to.throw(TypeError);
215
+ });
540
216
 
217
+ it("should throw a TypeError if the subject is not an object", function () {
218
+ expect(() => new Updater(element, null)).to.throw(TypeError);
219
+ });
220
+ });
221
+
222
+ describe("Runtime Error Handling", function () {
223
+ it("should add an error attribute if a value for data-monster-insert is not iterable", function (done) {
224
+ const element = document.getElementById("test1");
225
+ const u = new Updater(element, { a: { b: null } });
226
+ u.run()
227
+ .then(() => {
228
+ const expectedErrorMessage = "the value is not iterable";
229
+ expect(element).to.have.attribute(
230
+ "data-monster-error",
231
+ expectedErrorMessage,
232
+ );
233
+ done();
234
+ })
235
+ .catch((err) => {
236
+ done(
237
+ new Error(
238
+ "Promise was rejected but should have been resolved. Error: " +
239
+ err,
240
+ ),
241
+ );
541
242
  });
542
243
  });
244
+ });
543
245
  });
246
+ });
544
247
 
248
+ describe("Updater()", function () {
249
+ describe("new Updater", function () {
250
+ it("should return document object", function () {
251
+ let element = document.getElementById("test1");
545
252
 
546
- describe('Updater()', function () {
547
-
548
- beforeEach(() => {
549
- let mocks = document.getElementById('mocks');
550
- mocks.innerHTML = html3;
551
- })
552
-
553
- describe('Replace', function () {
554
-
555
- it('should ', function (done) {
556
- let element = document.getElementById('test1')
557
-
558
- let d = new Updater(
559
- element,
560
- {
561
- a: {
562
- b: [
563
- {i: '0'},
564
- ]
565
- }
566
- }
567
- );
253
+ let d = new Updater(element, {});
568
254
 
255
+ expect(typeof d).is.equal("object");
256
+ });
257
+ });
258
+ });
259
+
260
+ describe("Updater()", function () {
261
+ describe("Repeat", function () {
262
+ it("should build 6 li elements from an array", function (done) {
263
+ let element = document.getElementById("test1");
264
+ const testData = {
265
+ a: {
266
+ b: [
267
+ { i: "0" },
268
+ { i: "1" },
269
+ { i: "2" },
270
+ { i: "3" },
271
+ { i: "4" },
272
+ { i: "5" },
273
+ ],
274
+ },
275
+ };
276
+ let d = new Updater(element, testData);
277
+
278
+ d.run()
279
+ .then(() => {
280
+ const ul = element.querySelector("ul");
281
+ const listItems = ul.children;
282
+
283
+ // 1. Prüfe die korrekte Anzahl der Elemente
284
+ expect(listItems.length).to.equal(6);
285
+
286
+ // 2. Stichprobenartige Prüfung von Elementen
287
+ const firstItem = listItems[0];
288
+ expect(firstItem.tagName).to.equal("LI");
289
+ expect(firstItem).to.have.attribute(
290
+ "data-monster-insert-reference",
291
+ "current-0",
292
+ );
293
+ expect(firstItem.textContent).to.equal('{"i":"0"}');
294
+
295
+ const lastItem = listItems[5];
296
+ expect(lastItem).to.have.attribute(
297
+ "data-monster-insert-reference",
298
+ "current-5",
299
+ );
300
+ expect(lastItem.textContent).to.equal('{"i":"5"}');
301
+
302
+ done();
303
+ })
304
+ .catch(done);
305
+ });
306
+ });
307
+ });
569
308
 
570
- d.run().then(() => {
571
- setTimeout(() => {
572
- expect(typeof d).is.equal('object');
573
- expect(element).contain.html('<div data-monster-insert="myid path:a.b">');
574
- expect(element).contain.html('<p data-monster-insert="myinnerid path:a.b" data-monster-insert-reference="myid-0">');
575
- expect(element).contain.html('<span data-monster-replace="path:a.b.0 | tojson" data-monster-insert-reference="myinnerid-0">{"i":"0"}</span>');
309
+ describe("Updater()", function () {
310
+ beforeEach(() => {
311
+ let mocks = document.getElementById("mocks");
312
+ mocks.innerHTML = html4;
313
+ });
576
314
 
577
- done();
315
+ describe("Eventhandling", function () {
316
+ let updater, form1, proxyobserver;
317
+ beforeEach(() => {
318
+ proxyobserver = new ProxyObserver({});
319
+ updater = new Updater(document.getElementById("form1"), proxyobserver);
320
+ form1 = document.getElementById("form1");
321
+ });
322
+
323
+ // here click events are thrown on the checkbox and the setting of the value is observed via the proxyobserver.
324
+ it("should handle checkbox click events", function (done) {
325
+ updater.enableEventProcessing();
326
+
327
+ let subject = updater.getSubject();
328
+ expect(subject).is.equal(proxyobserver.getSubject());
329
+
330
+ let expected = ["checked", undefined, "checked"];
331
+ // here the notation with function is important, because the pointer is set.
332
+ proxyobserver.attachObserver(
333
+ new Observer(function () {
334
+ let e = expected.shift();
335
+ console.log(e, this.getSubject());
336
+ if (e === undefined && expected.length === 0)
337
+ done(new Error("to many calls"));
338
+
339
+ if (this.getSubject()["state"] !== e)
340
+ done(new Error(this.getSubject()["state"] + " should " + e));
341
+ if (expected.length === 0) {
342
+ done();
343
+ } else {
344
+ setTimeout(() => {
345
+ form1.querySelector("[name=checkbox]").click();
346
+ }, 10);
347
+ }
348
+ }),
349
+ );
350
+
351
+ setTimeout(() => {
352
+ form1.querySelector("[name=checkbox]").click();
353
+ }, 10);
354
+ });
355
+
356
+ it("should handle radio click events 1", function (done) {
357
+ updater.enableEventProcessing();
358
+
359
+ let subject = updater.getSubject();
360
+ expect(subject).is.equal(proxyobserver.getSubject());
361
+
362
+ let expected = ["r1", "r2", "r1"];
363
+ let clickTargets = ["r2", "r1"];
364
+ // here the notation with function is important, because the this pointer is set.
365
+ proxyobserver.attachObserver(
366
+ new Observer(function () {
367
+ let e = expected.shift();
368
+ if (e === undefined && expected.length === 0)
369
+ done(new Error("to many calls"));
370
+
371
+ let v = this.getSubject()["radio"];
372
+ if (v !== e) done(new Error(v + " should " + e));
373
+ if (expected.length === 0) {
374
+ done();
375
+ } else {
376
+ setTimeout(() => {
377
+ document.getElementById(clickTargets.shift()).click();
378
+ }, 10);
379
+ }
380
+ }),
381
+ );
382
+
383
+ setTimeout(() => {
384
+ document.getElementById("r1").click();
385
+ }, 10);
386
+
387
+ // no handler // bind
388
+ setTimeout(() => {
389
+ document.getElementById("rx").click();
390
+ }, 20);
391
+ });
392
+
393
+ it("should handle select click events 2", function (done) {
394
+ let selectElement = document.getElementById("select1");
395
+
396
+ updater.enableEventProcessing();
397
+
398
+ let subject = updater.getSubject();
399
+ expect(subject).is.equal(proxyobserver.getSubject());
400
+
401
+ let expected = ["value2", "value1", "value2"];
402
+ // here the notation with function is important, because the this pointer is set.
403
+ proxyobserver.attachObserver(
404
+ new Observer(function () {
405
+ let e = expected.shift();
406
+ if (e === undefined && expected.length === 0)
407
+ done(new Error("to many calls"));
408
+
409
+ let v = this.getSubject()["select"];
410
+ if (v !== e) done(new Error(v + " should " + e));
411
+ if (expected.length === 0) {
412
+ done();
413
+ } else {
414
+ setTimeout(() => {
415
+ selectElement.selectedIndex =
416
+ selectElement.selectedIndex === 1 ? 0 : 1;
417
+ selectElement.click();
418
+ }, 10);
419
+ }
420
+ }),
421
+ );
422
+
423
+ setTimeout(() => {
424
+ // set value and simulate click event for bubble
425
+ selectElement.selectedIndex = 1;
426
+ selectElement.click();
427
+ }, 20);
428
+ });
429
+
430
+ it("should handle textarea events", function (done) {
431
+ let textareaElement = document.getElementById("textarea");
432
+
433
+ updater.enableEventProcessing();
434
+
435
+ let subject = updater.getSubject();
436
+ expect(subject).is.equal(proxyobserver.getSubject());
437
+
438
+ let expected = ["testX", "lorem ipsum", ""];
439
+ let testValues = ["lorem ipsum", ""];
440
+ // here the notation with function is important, because the this pointer is set.
441
+ proxyobserver.attachObserver(
442
+ new Observer(function () {
443
+ let e = expected.shift();
444
+ if (e === undefined && expected.length === 0)
445
+ done(new Error("to many calls"));
446
+
447
+ let v = this.getSubject()["textarea"];
448
+ if (JSON.stringify(v) !== JSON.stringify(e))
449
+ done(
450
+ new Error(JSON.stringify(v) + " should " + JSON.stringify(e)),
451
+ );
452
+ if (expected.length === 0) {
453
+ done();
454
+ } else {
455
+ setTimeout(() => {
456
+ textareaElement.value = testValues.shift();
457
+ textareaElement.click();
458
+ }, 10);
459
+ }
460
+ }),
461
+ );
462
+
463
+ setTimeout(() => {
464
+ // set value and simulate click event for bubble
465
+ textareaElement.value = "testX";
466
+ textareaElement.click();
467
+ }, 20);
468
+ });
469
+
470
+ it("should handle multiple select events", function (done) {
471
+ let selectElement = document.getElementById("select2");
472
+
473
+ updater.enableEventProcessing();
474
+
475
+ let subject = updater.getSubject();
476
+ expect(subject).is.equal(proxyobserver.getSubject());
477
+
478
+ let expected = [
479
+ ["value1"],
480
+ ["value2", "value3", "value4"],
481
+ ["value1", "value4"],
482
+ ];
483
+
484
+ let testSelections = [
485
+ [false, true, true, true],
486
+ [true, false, false, true],
487
+ ];
488
+
489
+ // here the notation with function is important, because the this pointer is set.
490
+ proxyobserver.attachObserver(
491
+ new Observer(function () {
492
+ let e = expected.shift();
493
+ if (e === undefined && expected.length === 0)
494
+ done(new Error("to many calls"));
495
+
496
+ let v = this.getSubject()["multiselect"];
497
+
498
+ if (JSON.stringify(v) !== JSON.stringify(e))
499
+ done(
500
+ new Error(JSON.stringify(v) + " should " + JSON.stringify(e)),
501
+ );
502
+ if (expected.length === 0) {
503
+ done();
504
+ } else {
505
+ setTimeout(() => {
506
+ let v = testSelections.shift();
507
+ selectElement.options[0].selected = v[0];
508
+ selectElement.options[1].selected = v[1];
509
+ selectElement.options[2].selected = v[2];
510
+ selectElement.options[3].selected = v[3];
511
+ selectElement.click();
512
+ }, 10);
513
+ }
514
+ }),
515
+ );
516
+
517
+ setTimeout(() => {
518
+ selectElement.options[0].selected = true;
519
+ selectElement.options[1].selected = false;
520
+ selectElement.options[2].selected = false;
521
+ selectElement.options[3].selected = false;
522
+ selectElement.click();
523
+ }, 20);
524
+ });
525
+ });
526
+ });
578
527
 
579
- }, 100);
528
+ describe("Updater()", function () {
529
+ beforeEach(() => {
530
+ let mocks = document.getElementById("mocks");
531
+ mocks.innerHTML = html2;
532
+ });
580
533
 
581
- }).catch(
582
- e => {
583
- done(new Error(e))
584
- })
534
+ describe("Replace", function () {
535
+ it("should add lower hello and HELLOyes!", function (done) {
536
+ let element = document.getElementById("test1");
585
537
 
538
+ let d = new Updater(element, {
539
+ text: "HALLO",
540
+ });
586
541
 
587
- });
542
+ d.setCallback("myformatter", function (a) {
543
+ return a + "yes!";
588
544
  });
589
545
 
546
+ d.run()
547
+ .then(() => {
548
+ setTimeout(() => {
549
+ expect(typeof d).is.equal("object");
550
+ expect(element).contain.html(
551
+ '<div data-monster-replace="path:text | tolower">hallo</div>',
552
+ );
553
+ expect(element).contain.html(
554
+ '<div data-monster-replace="path:text | call:myformatter">HALLOyes!</div>',
555
+ );
556
+ expect(element).contain.html(
557
+ '<div data-monster-replace="static:hello\\ ">hello </div>',
558
+ );
559
+
560
+ return done();
561
+ }, 100);
562
+ })
563
+ .catch((e) => {
564
+ done(new Error(e));
565
+ });
566
+ });
590
567
  });
568
+ });
591
569
 
592
- describe('Updater()', function () {
593
- describe('Attributes', function () {
594
-
595
- it('should change attributes', function (done) {
596
- let element = document.getElementById('test3')
597
-
598
- let text = document.getElementById('text')
599
- expect(text.value).to.be.equal("");
600
-
601
- let radio = document.getElementById('radio')
602
- expect(radio.checked).to.be.false;
603
-
604
- let checkbox = document.getElementById('checkbox')
605
- expect(checkbox.checked).to.be.false;
606
-
607
- let select = document.getElementById('select')
608
- expect(select.selectedIndex).to.be.equal(0);
609
-
610
- let multiselect = document.getElementById('multiselect')
611
- expect(multiselect.selectedIndex).to.be.equal(-1);
612
-
613
- let textarea = document.getElementById('textarea')
614
- expect(textarea.value).to.be.equal("");
615
-
616
-
617
- let d = new Updater(
618
- element,
619
- {
620
- a: {
621
- b: "div-class",
622
- c: "hello",
623
- text: "hello",
624
- radio: "true",
625
- textarea: "test",
626
- multiselect: ['value3', 'value4', 'other-value5'],
627
- select: "value2",
628
- checkbox: "true"
629
- }
630
- }
631
- );
632
-
633
-
634
- d.run().then(() => {
635
-
636
- setTimeout(() => {
637
- expect(element).contain.html('<div data-monster-attributes="class path:a.b" class="div-class">');
638
- expect(element).contain.html('<input data-monster-attributes="value path:a.c" id="input1" value="hello">');
639
- expect(element).contain.html('<textarea name="textarea" id="textarea" data-monster-attributes="value path:a.textarea" value="test">');
640
- expect(element).contain.html('<input data-monster-attributes="checked path:a.radio" type="radio" name="radio" value="r1" id="radio" checked="true">');
641
-
642
- expect(text.value, 'text control').to.be.equal(d.getSubject()['a']['c']);
643
- expect(radio.checked, 'radio control').to.be.equal(true);
644
- expect(textarea.value, 'textarea control').to.be.equal(d.getSubject()['a']['textarea']);
645
- expect(select.selectedIndex, 'select control').to.be.equal(1); // [0=>other-value, 1=>value2]
646
-
647
- let multiselectSelectedOptions = [];
648
- for (const [index, obj] of Object.entries(multiselect.selectedOptions)) {
649
- multiselectSelectedOptions.push(obj.value);
650
- }
651
-
652
-
653
- expect(JSON.stringify(multiselectSelectedOptions), 'multiselect control').to.be.equal(JSON.stringify(d.getSubject()['a']['multiselect']));
654
- expect(checkbox.checked, 'checkbox control').to.be.true;
655
-
656
- done();
657
-
658
- }, 100);
659
-
660
- }).catch(
661
- e => {
662
- done(new Error(e))
663
- })
664
-
665
-
666
- });
667
- });
570
+ describe("Updater()", function () {
571
+ beforeEach(() => {
572
+ let mocks = document.getElementById("mocks");
573
+ mocks.innerHTML = html3;
668
574
  });
669
575
 
670
- describe('Get Attribute Pipe', function () {
671
- let id, mocks;
672
- beforeEach(() => {
673
- mocks = document.getElementById('mocks');
674
- id = new ID('monster');
675
- mocks.innerHTML = ` <div id="` + id + `"
676
- data-monster-replace="path:a | if:value:\\ "></div>`
677
- })
678
-
679
- afterEach(() => {
680
- mocks.innerHTML = "";
681
- })
682
-
683
- it('should include space', function () {
684
- const div = document.getElementById(id.toString())
685
-
686
- const pipe = div.getAttribute('data-monster-replace');
687
- expect(pipe.length).to.be.equal(20);
576
+ describe("Replace", function () {
577
+ it("should ", function (done) {
578
+ let element = document.getElementById("test1");
688
579
 
580
+ let d = new Updater(element, {
581
+ a: {
582
+ b: [{ i: "0" }],
583
+ },
689
584
  });
690
- });
691
585
 
586
+ d.run()
587
+ .then(() => {
588
+ setTimeout(() => {
589
+ expect(typeof d).is.equal("object");
590
+ expect(element).contain.html(
591
+ '<div data-monster-insert="myid path:a.b">',
592
+ );
593
+ expect(element).contain.html(
594
+ '<p data-monster-insert="myinnerid path:a.b" data-monster-insert-reference="myid-0">',
595
+ );
596
+ expect(element).contain.html(
597
+ '<span data-monster-replace="path:a.b.0 | tojson" data-monster-insert-reference="myinnerid-0">{"i":"0"}</span>',
598
+ );
599
+
600
+ done();
601
+ }, 100);
602
+ })
603
+ .catch((e) => {
604
+ done(new Error(e));
605
+ });
606
+ });
607
+ });
608
+ });
609
+
610
+ describe("Updater()", function () {
611
+ describe("Attributes", function () {
612
+ it("should change attributes", function (done) {
613
+ let element = document.getElementById("test3");
614
+
615
+ let text = document.getElementById("text");
616
+ expect(text.value).to.be.equal("");
617
+
618
+ let radio = document.getElementById("radio");
619
+ expect(radio.checked).to.be.false;
620
+
621
+ let checkbox = document.getElementById("checkbox");
622
+ expect(checkbox.checked).to.be.false;
623
+
624
+ let select = document.getElementById("select");
625
+ expect(select.selectedIndex).to.be.equal(0);
626
+
627
+ let multiselect = document.getElementById("multiselect");
628
+ expect(multiselect.selectedIndex).to.be.equal(-1);
629
+
630
+ let textarea = document.getElementById("textarea");
631
+ expect(textarea.value).to.be.equal("");
632
+
633
+ let d = new Updater(element, {
634
+ a: {
635
+ b: "div-class",
636
+ c: "hello",
637
+ text: "hello",
638
+ radio: "true",
639
+ textarea: "test",
640
+ multiselect: ["value3", "value4", "other-value5"],
641
+ select: "value2",
642
+ checkbox: "true",
643
+ },
644
+ });
692
645
 
693
- describe('manuel update', function () {
694
- let id, mocks;
646
+ d.run()
647
+ .then(() => {
648
+ setTimeout(() => {
649
+ expect(element).contain.html(
650
+ '<div data-monster-attributes="class path:a.b" class="div-class">',
651
+ );
652
+ expect(element).contain.html(
653
+ '<input data-monster-attributes="value path:a.c" id="input1" value="hello">',
654
+ );
655
+ expect(element).contain.html(
656
+ '<textarea name="textarea" id="textarea" data-monster-attributes="value path:a.textarea" value="test">',
657
+ );
658
+ expect(element).contain.html(
659
+ '<input data-monster-attributes="checked path:a.radio" type="radio" name="radio" value="r1" id="radio" checked="true">',
660
+ );
661
+
662
+ expect(text.value, "text control").to.be.equal(
663
+ d.getSubject()["a"]["c"],
664
+ );
665
+ expect(radio.checked, "radio control").to.be.equal(true);
666
+ expect(textarea.value, "textarea control").to.be.equal(
667
+ d.getSubject()["a"]["textarea"],
668
+ );
669
+ expect(select.selectedIndex, "select control").to.be.equal(1); // [0=>other-value, 1=>value2]
670
+
671
+ let multiselectSelectedOptions = [];
672
+ for (const [index, obj] of Object.entries(
673
+ multiselect.selectedOptions,
674
+ )) {
675
+ multiselectSelectedOptions.push(obj.value);
676
+ }
677
+
678
+ expect(
679
+ JSON.stringify(multiselectSelectedOptions),
680
+ "multiselect control",
681
+ ).to.be.equal(JSON.stringify(d.getSubject()["a"]["multiselect"]));
682
+ expect(checkbox.checked, "checkbox control").to.be.true;
683
+
684
+ done();
685
+ }, 100);
686
+ })
687
+ .catch((e) => {
688
+ done(new Error(e));
689
+ });
690
+ });
691
+ });
692
+ });
695
693
 
696
- beforeEach(() => {
697
- mocks = document.getElementById('mocks');
698
- id = new ID('monster').toString();
699
- mocks.innerHTML = `<input id="` + id + `"data-monster-bind="path:myvalue">`
700
- })
694
+ describe("Get Attribute Pipe", function () {
695
+ let id, mocks;
696
+ beforeEach(() => {
697
+ mocks = document.getElementById("mocks");
698
+ id = new ID("monster");
699
+ mocks.innerHTML =
700
+ ` <div id="` +
701
+ id +
702
+ `"
703
+ data-monster-replace="path:a | if:value:\\ "></div>`;
704
+ });
701
705
 
702
- afterEach(() => {
703
- mocks.innerHTML = "";
704
- })
706
+ afterEach(() => {
707
+ mocks.innerHTML = "";
708
+ });
705
709
 
706
- it('should get value', function () {
710
+ it("should include space", function () {
711
+ const div = document.getElementById(id.toString());
707
712
 
708
- document.getElementById(id).value = "hello";
709
- const updater = new Updater(mocks);
710
- const subject = updater.getSubject();
713
+ const pipe = div.getAttribute("data-monster-replace");
714
+ expect(pipe.length).to.be.equal(20);
715
+ });
716
+ });
711
717
 
712
- expect(subject).to.not.have.property('myvalue');
713
- updater.retrieve();
714
- expect(subject).to.have.property('myvalue');
715
- });
718
+ describe("manuel update", function () {
719
+ let id, mocks;
716
720
 
721
+ beforeEach(() => {
722
+ mocks = document.getElementById("mocks");
723
+ id = new ID("monster").toString();
724
+ mocks.innerHTML =
725
+ `<input id="` + id + `"data-monster-bind="path:myvalue">`;
726
+ });
717
727
 
728
+ afterEach(() => {
729
+ mocks.innerHTML = "";
718
730
  });
719
731
 
732
+ it("should get value", function () {
733
+ document.getElementById(id).value = "hello";
734
+ const updater = new Updater(mocks);
735
+ const subject = updater.getSubject();
720
736
 
721
- /**
722
- * https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/112
723
- */
724
- describe('Updater() 20220107', function () {
737
+ expect(subject).to.not.have.property("myvalue");
738
+ updater.retrieve();
739
+ expect(subject).to.have.property("myvalue");
740
+ });
741
+ });
725
742
 
726
- beforeEach(() => {
727
- let mocks = document.getElementById('mocks');
728
- // language=HTML
729
- mocks.innerHTML = `
743
+ /**
744
+ * https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/112
745
+ */
746
+ describe("Updater() 20220107", function () {
747
+ beforeEach(() => {
748
+ let mocks = document.getElementById("mocks");
749
+ // language=HTML
750
+ mocks.innerHTML = `
730
751
 
731
752
  <div id="container">
732
753
  <div data-monster-replace="path:content"></div>
@@ -734,63 +755,55 @@ describe('DOM', function () {
734
755
 
735
756
 
736
757
  `;
737
- })
738
-
739
- describe('Bugfix #112', function () {
740
-
741
- it('should add ', function (done) {
742
- let containerElement = document.getElementById('container');
743
- let newElement = document.createElement('div');
744
- newElement.innerHTML = 'yeah! <b>Test</b>!';
758
+ });
745
759
 
746
- const containerHTML = containerElement.innerHTML;
747
- const newHTML = newElement.innerHTML;
760
+ describe("Bugfix #112", function () {
761
+ it("should add ", function (done) {
762
+ let containerElement = document.getElementById("container");
763
+ let newElement = document.createElement("div");
764
+ newElement.innerHTML = "yeah! <b>Test</b>!";
748
765
 
749
- let d = new Updater(
750
- containerElement,
751
- {
752
- content: newElement
753
- }
754
- );
755
- setTimeout(() => {
756
- d.run().then(() => {
757
-
758
- setTimeout(() => {
759
-
760
- try {
761
- expect(containerElement).contain.html('<div>yeah! <b>Test</b>!</div>');
762
- } catch (e) {
763
- return done(e);
764
- }
765
-
766
-
767
- done()
768
- }, 100)
769
- })
770
- }, 100)
771
-
772
- // d.setCallback('myformatter', function (a) {
773
- // return a + 'yes!'
774
- // })
775
- //
776
- // setTimeout(() => {
777
- // d.run().then(() => {
778
- //
779
- // expect(typeof d).is.equal('object');
780
- // expect(element).contain.html('<div data-monster-replace="path:text | tolower">hallo</div>');
781
- // expect(element).contain.html('<div data-monster-replace="path:text | call:myformatter">HALLOyes!</div>');
782
- // expect(element).contain.html('<div data-monster-replace="static:hello\\ ">hello </div>');
783
- //
784
- // return done();
785
- // }).catch(
786
- // e => {
787
- // done(new Error(e))
788
- // })
789
- // }, 100)
766
+ const containerHTML = containerElement.innerHTML;
767
+ const newHTML = newElement.innerHTML;
790
768
 
791
- });
769
+ let d = new Updater(containerElement, {
770
+ content: newElement,
792
771
  });
772
+ setTimeout(() => {
773
+ d.run().then(() => {
774
+ setTimeout(() => {
775
+ try {
776
+ expect(containerElement).contain.html(
777
+ "<div>yeah! <b>Test</b>!</div>",
778
+ );
779
+ } catch (e) {
780
+ return done(e);
781
+ }
782
+
783
+ done();
784
+ }, 100);
785
+ });
786
+ }, 100);
787
+
788
+ // d.setCallback('myformatter', function (a) {
789
+ // return a + 'yes!'
790
+ // })
791
+ //
792
+ // setTimeout(() => {
793
+ // d.run().then(() => {
794
+ //
795
+ // expect(typeof d).is.equal('object');
796
+ // expect(element).contain.html('<div data-monster-replace="path:text | tolower">hallo</div>');
797
+ // expect(element).contain.html('<div data-monster-replace="path:text | call:myformatter">HALLOyes!</div>');
798
+ // expect(element).contain.html('<div data-monster-replace="static:hello\\ ">hello </div>');
799
+ //
800
+ // return done();
801
+ // }).catch(
802
+ // e => {
803
+ // done(new Error(e))
804
+ // })
805
+ // }, 100)
806
+ });
793
807
  });
794
-
795
-
796
- });
808
+ });
809
+ });