@schukai/monster 4.128.2 → 4.128.3
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.
- package/package.json +1 -1
- package/source/components/content/stylesheet/camera-capture.mjs +1 -1
- package/source/components/content/stylesheet/copy.mjs +1 -1
- package/source/components/content/viewer/stylesheet/message.mjs +1 -1
- package/source/components/datatable/columnbar.mjs +30 -3
- package/source/components/datatable/datatable.mjs +26 -1
- package/source/components/datatable/stylesheet/filter-controls-defaults.mjs +1 -1
- package/source/components/form/stylesheet/button-bar.mjs +1 -1
- package/source/components/form/stylesheet/confirm-button.mjs +1 -1
- package/source/components/form/stylesheet/context-error.mjs +1 -1
- package/source/components/form/stylesheet/context-help.mjs +1 -1
- package/source/components/form/stylesheet/digits.mjs +1 -1
- package/source/components/form/stylesheet/field-set.mjs +1 -1
- package/source/components/form/stylesheet/login.mjs +1 -1
- package/source/components/form/stylesheet/popper-button.mjs +1 -1
- package/source/components/form/stylesheet/select.mjs +1 -1
- package/source/components/layout/stylesheet/popper.mjs +1 -1
- package/source/components/style/floating-ui.css +7 -0
- package/source/dom/customcontrol.mjs +1 -1
- package/source/dom/customelement.mjs +37 -15
- package/source/dom/updater.mjs +32 -12
- package/source/types/is.mjs +3 -0
- package/source/types/proxyobserver.mjs +10 -13
- package/source/types/version.mjs +1 -1
- package/test/cases/components/content/image-editor.mjs +98 -0
- package/test/cases/components/datatable/drag-scroll.mjs +218 -14
- package/test/cases/components/form/select.mjs +70 -32
- package/test/cases/dom/customcontrol.mjs +44 -10
- package/test/cases/dom/customelement-initfromscripthost.mjs +22 -1
- package/test/cases/dom/customelement.mjs +83 -0
- package/test/cases/dom/updater.mjs +98 -0
- package/test/cases/monster.mjs +1 -1
- package/test/cases/types/proxyobserver.mjs +31 -0
- package/test/web/import.js +3 -0
- package/test/web/puppeteer.mjs +94 -71
- package/test/web/test.html +29 -2
- package/test/web/tests.js +25120 -15937
|
@@ -161,9 +161,9 @@ describe('DOM', function () {
|
|
|
161
161
|
//
|
|
162
162
|
// })
|
|
163
163
|
|
|
164
|
-
|
|
164
|
+
describe('Test ElementInternals', function () {
|
|
165
165
|
|
|
166
|
-
|
|
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
|
-
|
|
279
|
+
it('setValidity()', function () {
|
|
280
280
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
|
|
@@ -133,7 +133,28 @@ describe('DOM', function () {
|
|
|
133
133
|
expect(control.hasAttribute('data-monster-error')).is.false;
|
|
134
134
|
|
|
135
135
|
});
|
|
136
|
+
|
|
137
|
+
it('should resolve callback hosts from a comma separated list', function () {
|
|
138
|
+
let mocks = document.getElementById('mocks');
|
|
139
|
+
mocks.innerHTML = `
|
|
140
|
+
<div id="call-back-host-1"></div>
|
|
141
|
+
<div id="call-back-host-2"></div>
|
|
142
|
+
<div id="container"></div>
|
|
143
|
+
`;
|
|
144
|
+
|
|
145
|
+
const container = document.getElementById('call-back-host-2');
|
|
146
|
+
container.initCustomControlCallback = function (control) {
|
|
147
|
+
control.setOption('test', 3);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
let control = document.createElement(randomTagNumber);
|
|
151
|
+
control.setAttribute('data-monster-script-host', "call-back-host-1,call-back-host-2");
|
|
152
|
+
document.getElementById('container').appendChild(control);
|
|
153
|
+
|
|
154
|
+
expect(control.getOption('test')).is.eql(3);
|
|
155
|
+
expect(control.hasAttribute('data-monster-error')).is.false;
|
|
156
|
+
});
|
|
136
157
|
})
|
|
137
158
|
|
|
138
159
|
});
|
|
139
|
-
})
|
|
160
|
+
})
|
|
@@ -321,6 +321,89 @@ describe('DOM', function () {
|
|
|
321
321
|
});
|
|
322
322
|
});
|
|
323
323
|
|
|
324
|
+
describe('shadow root lifecycle', function () {
|
|
325
|
+
it('should support closed shadow roots without adding an error', function (done) {
|
|
326
|
+
const htmlTAG = 'monster-testclass-closed';
|
|
327
|
+
|
|
328
|
+
class ClosedShadowComponent extends CustomElement {
|
|
329
|
+
static getTag() {
|
|
330
|
+
return htmlTAG;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
get defaults() {
|
|
334
|
+
return Object.assign({}, super.defaults, {
|
|
335
|
+
shadowMode: 'closed',
|
|
336
|
+
templates: {
|
|
337
|
+
main: '<span id="inside">ok</span>'
|
|
338
|
+
},
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
registerCustomElement(ClosedShadowComponent);
|
|
344
|
+
|
|
345
|
+
let d = document.createElement(htmlTAG);
|
|
346
|
+
document.getElementById('test1').appendChild(d);
|
|
347
|
+
|
|
348
|
+
setTimeout(function () {
|
|
349
|
+
try {
|
|
350
|
+
expect(d.hasAttribute('data-monster-error')).to.be.false;
|
|
351
|
+
expect(d.shadowRoot).to.equal(null);
|
|
352
|
+
done();
|
|
353
|
+
} catch (e) {
|
|
354
|
+
done(e);
|
|
355
|
+
}
|
|
356
|
+
}, 10);
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
describe('attribute lifecycle', function () {
|
|
361
|
+
it('should not double-call attributeChangedCallback for observed attributes', function (done) {
|
|
362
|
+
const htmlTAG = 'monster-testclass-observed';
|
|
363
|
+
|
|
364
|
+
class ObservedAttributeComponent extends CustomElement {
|
|
365
|
+
static getTag() {
|
|
366
|
+
return htmlTAG;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
static get observedAttributes() {
|
|
370
|
+
return ['data-demo'];
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
get defaults() {
|
|
374
|
+
return Object.assign({}, super.defaults, {
|
|
375
|
+
shadowMode: false,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
constructor() {
|
|
380
|
+
super();
|
|
381
|
+
this.attributeChangedCalls = [];
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
attributeChangedCallback(attrName, oldVal, newVal) {
|
|
385
|
+
this.attributeChangedCalls.push([attrName, oldVal, newVal]);
|
|
386
|
+
super.attributeChangedCallback(attrName, oldVal, newVal);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
registerCustomElement(ObservedAttributeComponent);
|
|
391
|
+
|
|
392
|
+
let d = document.createElement(htmlTAG);
|
|
393
|
+
document.getElementById('test1').appendChild(d);
|
|
394
|
+
d.setAttribute('data-demo', '1');
|
|
395
|
+
|
|
396
|
+
setTimeout(function () {
|
|
397
|
+
try {
|
|
398
|
+
expect(d.attributeChangedCalls).to.have.length(1);
|
|
399
|
+
done();
|
|
400
|
+
} catch (e) {
|
|
401
|
+
done(e);
|
|
402
|
+
}
|
|
403
|
+
}, 10);
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
|
|
324
407
|
describe('Options change', function () {
|
|
325
408
|
|
|
326
409
|
it('delegatesFocus should change from true to false', function () {
|
|
@@ -1907,5 +1907,103 @@ describe("DOM", function () {
|
|
|
1907
1907
|
})
|
|
1908
1908
|
.catch((e) => done(e));
|
|
1909
1909
|
});
|
|
1910
|
+
|
|
1911
|
+
it("should update every parent-path binding when a nested path changes", function (done) {
|
|
1912
|
+
let mocks = document.getElementById("mocks");
|
|
1913
|
+
mocks.innerHTML = `
|
|
1914
|
+
<div id="nested-parent-1" data-monster-replace="path:a | tojson"></div>
|
|
1915
|
+
<div id="nested-leaf" data-monster-replace="path:a.b"></div>
|
|
1916
|
+
<div id="nested-parent-2" data-monster-replace="path:a | tojson"></div>
|
|
1917
|
+
`;
|
|
1918
|
+
|
|
1919
|
+
const updater = new Updater(mocks, { a: { b: "first" } });
|
|
1920
|
+
|
|
1921
|
+
updater
|
|
1922
|
+
.run()
|
|
1923
|
+
.then(() => {
|
|
1924
|
+
updater.getSubject().a.b = "second";
|
|
1925
|
+
|
|
1926
|
+
setTimeout(() => {
|
|
1927
|
+
try {
|
|
1928
|
+
expect(document.getElementById("nested-parent-1").textContent).to.equal(
|
|
1929
|
+
'{"b":"second"}',
|
|
1930
|
+
);
|
|
1931
|
+
expect(document.getElementById("nested-leaf").textContent).to.equal(
|
|
1932
|
+
"second",
|
|
1933
|
+
);
|
|
1934
|
+
expect(document.getElementById("nested-parent-2").textContent).to.equal(
|
|
1935
|
+
'{"b":"second"}',
|
|
1936
|
+
);
|
|
1937
|
+
done();
|
|
1938
|
+
} catch (e) {
|
|
1939
|
+
done(e);
|
|
1940
|
+
}
|
|
1941
|
+
}, 50);
|
|
1942
|
+
})
|
|
1943
|
+
.catch((e) => done(e));
|
|
1944
|
+
});
|
|
1945
|
+
|
|
1946
|
+
it('should keep "0" for optional number bindings', function (done) {
|
|
1947
|
+
let mocks = document.getElementById("mocks");
|
|
1948
|
+
mocks.innerHTML = `
|
|
1949
|
+
<input id="optional-number" data-monster-bind="path:value" data-monster-bind-type="number?">
|
|
1950
|
+
`;
|
|
1951
|
+
|
|
1952
|
+
const updater = new Updater(mocks, {});
|
|
1953
|
+
updater.enableEventProcessing();
|
|
1954
|
+
|
|
1955
|
+
const input = document.getElementById("optional-number");
|
|
1956
|
+
input.value = "0";
|
|
1957
|
+
input.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
|
|
1958
|
+
|
|
1959
|
+
setTimeout(() => {
|
|
1960
|
+
try {
|
|
1961
|
+
expect(updater.getSubject().value).to.equal(0);
|
|
1962
|
+
done();
|
|
1963
|
+
} catch (e) {
|
|
1964
|
+
done(e);
|
|
1965
|
+
}
|
|
1966
|
+
}, 80);
|
|
1967
|
+
});
|
|
1968
|
+
|
|
1969
|
+
it("should clear select attributes when bound values become undefined", function (done) {
|
|
1970
|
+
let mocks = document.getElementById("mocks");
|
|
1971
|
+
mocks.innerHTML = `
|
|
1972
|
+
<select id="select-one" data-monster-attributes="value path:single">
|
|
1973
|
+
<option value="a">a</option>
|
|
1974
|
+
<option value="b">b</option>
|
|
1975
|
+
</select>
|
|
1976
|
+
<select id="select-multiple" multiple data-monster-attributes="value path:multiple">
|
|
1977
|
+
<option value="a">a</option>
|
|
1978
|
+
<option value="b">b</option>
|
|
1979
|
+
</select>
|
|
1980
|
+
`;
|
|
1981
|
+
|
|
1982
|
+
const updater = new Updater(mocks, {
|
|
1983
|
+
single: "b",
|
|
1984
|
+
multiple: ["a"],
|
|
1985
|
+
});
|
|
1986
|
+
|
|
1987
|
+
updater
|
|
1988
|
+
.run()
|
|
1989
|
+
.then(() => {
|
|
1990
|
+
updater.getSubject().single = undefined;
|
|
1991
|
+
updater.getSubject().multiple = undefined;
|
|
1992
|
+
|
|
1993
|
+
setTimeout(() => {
|
|
1994
|
+
try {
|
|
1995
|
+
const selectOne = document.getElementById("select-one");
|
|
1996
|
+
const selectMultiple = document.getElementById("select-multiple");
|
|
1997
|
+
expect(selectOne.selectedIndex).to.equal(-1);
|
|
1998
|
+
expect(Array.from(selectMultiple.selectedOptions)).to.have.length(0);
|
|
1999
|
+
expect(mocks.hasAttribute("data-monster-error")).to.be.false;
|
|
2000
|
+
done();
|
|
2001
|
+
} catch (e) {
|
|
2002
|
+
done(e);
|
|
2003
|
+
}
|
|
2004
|
+
}, 50);
|
|
2005
|
+
})
|
|
2006
|
+
.catch((e) => done(e));
|
|
2007
|
+
});
|
|
1910
2008
|
});
|
|
1911
2009
|
});
|
package/test/cases/monster.mjs
CHANGED
|
@@ -261,4 +261,35 @@ describe('ProxyObserver', function () {
|
|
|
261
261
|
});
|
|
262
262
|
});
|
|
263
263
|
|
|
264
|
+
describe('runtime compatibility', function () {
|
|
265
|
+
it('should allow nested object access without DOM globals', function () {
|
|
266
|
+
const proxy = new ProxyObserver({options: {enabled: true}});
|
|
267
|
+
expect(proxy.getSubject().options.enabled).to.equal(true);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('should preserve setter semantics for accessor-backed instances', function () {
|
|
271
|
+
let setterCalls = 0;
|
|
272
|
+
|
|
273
|
+
class Example {
|
|
274
|
+
set value(v) {
|
|
275
|
+
setterCalls++;
|
|
276
|
+
this._value = v;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
get value() {
|
|
280
|
+
return this._value;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const instance = new Example();
|
|
285
|
+
const proxy = new ProxyObserver({instance});
|
|
286
|
+
|
|
287
|
+
proxy.getSubject().instance.value = 7;
|
|
288
|
+
|
|
289
|
+
expect(setterCalls).to.equal(1);
|
|
290
|
+
expect(instance.value).to.equal(7);
|
|
291
|
+
expect(Object.prototype.hasOwnProperty.call(instance, 'value')).to.be.false;
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
264
295
|
})
|
package/test/web/import.js
CHANGED
|
@@ -3,6 +3,7 @@ import "./prepare.js";
|
|
|
3
3
|
import "../cases/components/layout/tabs.mjs";
|
|
4
4
|
import "../cases/components/layout/slit-panel.mjs";
|
|
5
5
|
import "../cases/components/layout/panel.mjs";
|
|
6
|
+
import "../cases/components/content/image-editor.mjs";
|
|
6
7
|
import "../cases/components/form/buy-box.mjs";
|
|
7
8
|
import "../cases/components/form/message-state-button.mjs";
|
|
8
9
|
import "../cases/components/form/button-bar.mjs";
|
|
@@ -12,6 +13,7 @@ import "../cases/components/form/select.mjs";
|
|
|
12
13
|
import "../cases/components/form/confirm-button.mjs";
|
|
13
14
|
import "../cases/components/form/form.mjs";
|
|
14
15
|
import "../cases/components/form/tree-select.mjs";
|
|
16
|
+
import "../cases/components/form/wizard.mjs";
|
|
15
17
|
import "../cases/components/form/button.mjs";
|
|
16
18
|
import "../cases/components/form/toggle-switch.mjs";
|
|
17
19
|
import "../cases/components/form/template.mjs";
|
|
@@ -21,6 +23,7 @@ import "../cases/components/host/host.mjs";
|
|
|
21
23
|
import "../cases/components/host/overlay.mjs";
|
|
22
24
|
import "../cases/components/host/util.mjs";
|
|
23
25
|
import "../cases/components/host/details.mjs";
|
|
26
|
+
import "../cases/components/datatable/drag-scroll.mjs";
|
|
24
27
|
import "../cases/components/datatable/writeback-sanitizer.mjs";
|
|
25
28
|
import "../cases/components/datatable/pagination.mjs";
|
|
26
29
|
import "../cases/text/formatter.mjs";
|
package/test/web/puppeteer.mjs
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import puppeteer from 'puppeteer';
|
|
2
2
|
import {unlinkSync} from 'fs';
|
|
3
3
|
import {existsSync} from 'fs';
|
|
4
|
+
import {mkdtempSync, rmSync} from 'fs';
|
|
5
|
+
import {tmpdir} from 'os';
|
|
6
|
+
import path from 'path';
|
|
4
7
|
|
|
5
8
|
|
|
6
9
|
// args auswerten mit --path und --browser, get from args
|
|
@@ -30,82 +33,102 @@ if (!config.browser) {
|
|
|
30
33
|
|
|
31
34
|
|
|
32
35
|
(async () => {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
const userDataDir = mkdtempSync(path.join(tmpdir(), 'monster-webtest-'));
|
|
37
|
+
let browser;
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
try {
|
|
41
|
+
browser = await puppeteer.launch({
|
|
42
|
+
headless: 'new', // if you want to see the browser, set this to false
|
|
43
|
+
executablePath: config.browser,
|
|
44
|
+
//args: ['--no-sandbox',"--window-size=1440,1000", "--no-sandbox", "--disable-setuid-sandbox", "--disable-gpu"],
|
|
45
|
+
args: ["--disable-gpu",
|
|
46
|
+
'--no-sandbox',
|
|
47
|
+
'--disable-setuid-sandbox',
|
|
48
|
+
`--user-data-dir=${userDataDir}`,
|
|
49
|
+
'--enable-logging=stderr',
|
|
50
|
+
'--disable-web-security',
|
|
51
|
+
'--disable-features=IsolateOrigins',
|
|
52
|
+
'--disable-site-isolation-trials',
|
|
53
|
+
'--disable-crash-reporter',
|
|
54
|
+
'--disable-breakpad',
|
|
55
|
+
'--no-first-run',
|
|
56
|
+
'--no-default-browser-check',
|
|
57
|
+
'--disable-dev-shm-usage'
|
|
58
|
+
],
|
|
59
|
+
|
|
60
|
+
userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36',
|
|
61
|
+
waitUntil: 'load',
|
|
62
|
+
timeout: 0,
|
|
63
|
+
protocolTimeout: 0,
|
|
64
|
+
dumpio: true
|
|
65
|
+
});
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error('Browser launch failed');
|
|
68
|
+
console.error(`Browser executable: ${config.browser}`);
|
|
69
|
+
console.error(`Browser profile: ${userDataDir}`);
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const page = await browser.newPage();
|
|
74
|
+
const fileUrl = 'file://' + config.path;
|
|
75
|
+
|
|
76
|
+
console.log('Loading page... '+fileUrl);
|
|
77
|
+
|
|
78
|
+
await page.goto(fileUrl, {waitUntil: 'load', timeout: 0});
|
|
79
|
+
|
|
80
|
+
const title = await page.title();
|
|
81
|
+
console.log('Page title:', title);
|
|
82
|
+
|
|
83
|
+
// page.on('console', async e => {
|
|
84
|
+
// const args = await Promise.all(e.args().map(a => a.jsonValue()));
|
|
85
|
+
// console[e.type() === 'warning' ? 'warn' : e.type()](...args);
|
|
86
|
+
// });
|
|
87
|
+
//
|
|
88
|
+
//
|
|
89
|
+
//
|
|
90
|
+
console.log('Running tests...');
|
|
91
|
+
await page.waitForFunction('document.getElementById("mocha-done").textContent.length > 0',
|
|
92
|
+
{
|
|
93
|
+
timeout: 1000000,
|
|
94
|
+
polling: 1000
|
|
95
|
+
}
|
|
96
|
+
) ;
|
|
97
|
+
|
|
98
|
+
const passes = await page.evaluate(() => document.getElementById('mocha-stats').querySelector('li.passes em').textContent);
|
|
99
|
+
const failures = await page.evaluate(() => document.getElementById('mocha-stats').querySelector('li.failures em').textContent);
|
|
100
|
+
const duration = await page.evaluate(() => document.getElementById('mocha-stats').querySelector('li.duration em').textContent);
|
|
101
|
+
|
|
102
|
+
console.log('Tests passed:', passes);
|
|
103
|
+
console.log('Tests failed:', failures);
|
|
104
|
+
console.log('Duration:', duration);
|
|
46
105
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
timeout: 0,
|
|
50
|
-
protocolTimeout: 0,
|
|
51
|
-
dumpio: true
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
const page = await browser.newPage();
|
|
55
|
-
const fileUrl = 'file://' + config.path;
|
|
56
|
-
|
|
57
|
-
console.log('Loading page... '+fileUrl);
|
|
58
|
-
|
|
59
|
-
await page.goto(fileUrl, {waitUntil: 'load', timeout: 0});
|
|
60
|
-
|
|
61
|
-
const title = await page.title();
|
|
62
|
-
console.log('Page title:', title);
|
|
63
|
-
|
|
64
|
-
// page.on('console', async e => {
|
|
65
|
-
// const args = await Promise.all(e.args().map(a => a.jsonValue()));
|
|
66
|
-
// console[e.type() === 'warning' ? 'warn' : e.type()](...args);
|
|
67
|
-
// });
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
console.log('Running tests...');
|
|
72
|
-
await page.waitForFunction('document.getElementById("mocha-done").textContent.length > 0',
|
|
73
|
-
{
|
|
74
|
-
timeout: 1000000,
|
|
75
|
-
polling: 1000
|
|
106
|
+
if (existsSync('screenshot.png')) {
|
|
107
|
+
unlinkSync('screenshot.png');
|
|
76
108
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const passes = await page.evaluate(() => document.getElementById('mocha-stats').querySelector('li.passes em').textContent);
|
|
80
|
-
const failures = await page.evaluate(() => document.getElementById('mocha-stats').querySelector('li.failures em').textContent);
|
|
81
|
-
const duration = await page.evaluate(() => document.getElementById('mocha-stats').querySelector('li.duration em').textContent);
|
|
82
|
-
|
|
83
|
-
console.log('Tests passed:', passes);
|
|
84
|
-
console.log('Tests failed:', failures);
|
|
85
|
-
console.log('Duration:', duration);
|
|
86
|
-
|
|
87
|
-
if (existsSync('screenshot.png')) {
|
|
88
|
-
unlinkSync('screenshot.png');
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
await page.screenshot({ path: 'screenshot.png' });
|
|
109
|
+
|
|
110
|
+
await page.screenshot({ path: 'screenshot.png' });
|
|
92
111
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
112
|
+
const failuresAsInt = parseInt(failures);
|
|
113
|
+
if (failuresAsInt > 0) {
|
|
114
|
+
console.error('Tests failed');
|
|
96
115
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
116
|
+
await page.evaluate(() => {
|
|
117
|
+
document.querySelectorAll('.test.fail').forEach((node) => {
|
|
118
|
+
console.error(node.textContent);
|
|
119
|
+
});
|
|
100
120
|
});
|
|
101
|
-
});
|
|
102
121
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
122
|
+
process.exitCode = 1;
|
|
123
|
+
} else {
|
|
124
|
+
console.log('Tests passed');
|
|
125
|
+
}
|
|
126
|
+
} finally {
|
|
127
|
+
if (browser) {
|
|
128
|
+
await browser.close().catch(() => {});
|
|
129
|
+
}
|
|
109
130
|
|
|
131
|
+
rmSync(userDataDir, { recursive: true, force: true });
|
|
132
|
+
}
|
|
110
133
|
|
|
111
|
-
})();
|
|
134
|
+
})();
|
package/test/web/test.html
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="headline" style="display: flex;align-items: center;justify-content: center;flex-direction: column;">
|
|
12
|
-
<h1 style='margin-bottom: 0.1em;'>Monster 4.
|
|
13
|
-
<div id="lastupdate" style='font-size:0.7em'>last update
|
|
12
|
+
<h1 style='margin-bottom: 0.1em;'>Monster 4.128.2</h1>
|
|
13
|
+
<div id="lastupdate" style='font-size:0.7em'>last update Do 26. Mär 19:17:38 CET 2026</div>
|
|
14
14
|
</div>
|
|
15
15
|
<div id="mocha-errors"
|
|
16
16
|
style="color: red;font-weight: bold;display: flex;align-items: center;justify-content: center;flex-direction: column;margin:20px;"></div>
|
|
@@ -26,8 +26,24 @@
|
|
|
26
26
|
<script>
|
|
27
27
|
|
|
28
28
|
try {
|
|
29
|
+
const ignoredBrowserErrorMessages = new Set([
|
|
30
|
+
"ResizeObserver loop completed with undelivered notifications.",
|
|
31
|
+
"ResizeObserver loop limit exceeded",
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
const isIgnoredBrowserError = (message, error) => {
|
|
35
|
+
const normalizedMessage = typeof message === "string" && message !== ""
|
|
36
|
+
? message
|
|
37
|
+
: error?.message;
|
|
38
|
+
return ignoredBrowserErrorMessages.has(normalizedMessage);
|
|
39
|
+
};
|
|
29
40
|
|
|
30
41
|
addEventListener("error", (event) => {
|
|
42
|
+
if (isIgnoredBrowserError(event.message, event.error)) {
|
|
43
|
+
event.preventDefault?.();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
31
47
|
document.getElementById('mocha-errors').insertAdjacentHTML("afterbegin", event.message);
|
|
32
48
|
document.getElementById('mocha-stats').style.backgroundColor = 'red';
|
|
33
49
|
});
|
|
@@ -41,6 +57,17 @@
|
|
|
41
57
|
|
|
42
58
|
});
|
|
43
59
|
|
|
60
|
+
const mochaOnError = window.onerror;
|
|
61
|
+
if (typeof mochaOnError === "function") {
|
|
62
|
+
window.onerror = function(message, source, line, column, error) {
|
|
63
|
+
if (isIgnoredBrowserError(message, error)) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return mochaOnError.call(this, message, source, line, column, error);
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
44
71
|
runner.on('end', function () {
|
|
45
72
|
document.getElementById('mocha-done').insertAdjacentHTML("afterbegin", 'the execution is done');
|
|
46
73
|
document.getElementById('lastupdate').innerHTML = 'last update ' + new Date();
|