@schukai/monster 4.70.1 → 4.70.2
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/CHANGELOG.md +12 -0
- package/package.json +1 -1
- package/source/components/form/select.mjs +2 -1
- package/source/types/version.mjs +1 -1
- package/test/cases/components/form/select.mjs +56 -0
- package/test/cases/data/datasource/server/restapi.mjs +40 -3
- package/test/cases/data/datasource/server/websocket.mjs +1 -2
- package/test/cases/data/datasource.mjs +21 -1
- package/test/cases/dom/customelement.mjs +4 -1
- package/test/cases/dom/resource/link/stylesheet.mjs +15 -4
- package/test/cases/dom/resource/link.mjs +15 -4
- package/test/cases/dom/resource/script.mjs +15 -4
- package/test/cases/dom/updater.mjs +29 -0
- package/test/cases/monster.mjs +1 -1
- package/test/cases/types/proxyobserver.mjs +31 -0
- package/test/util/jsdom.mjs +42 -8
- package/test/util/websocket.mjs +38 -18
- package/test/web/test.html +2 -2
- package/test/web/tests.js +297 -65
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.4","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.70.
|
|
1
|
+
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.4","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.70.2"}
|
|
@@ -2967,8 +2967,9 @@ function areOptionsAvailableAndInitInternal() {
|
|
|
2967
2967
|
this[areOptionsAvailableAndInitSymbol]++;
|
|
2968
2968
|
|
|
2969
2969
|
let options = this.getOption("options");
|
|
2970
|
+
const currentOptions = options;
|
|
2970
2971
|
|
|
2971
|
-
if (isArray(options) &&
|
|
2972
|
+
if (isArray(options) && options.length === 1 && isString(options?.[0])) {
|
|
2972
2973
|
try {
|
|
2973
2974
|
const obj = JSON.parse(options[0]);
|
|
2974
2975
|
if (isArray(obj)) {
|
package/source/types/version.mjs
CHANGED
|
@@ -216,6 +216,62 @@ describe('Select', function () {
|
|
|
216
216
|
|
|
217
217
|
});
|
|
218
218
|
|
|
219
|
+
it('should normalize options without throwing', function (done) {
|
|
220
|
+
this.timeout(2000);
|
|
221
|
+
|
|
222
|
+
let mocks = document.getElementById('mocks');
|
|
223
|
+
const select = document.createElement('monster-select');
|
|
224
|
+
select.setOption('options', [
|
|
225
|
+
{label: 'Alpha'},
|
|
226
|
+
{value: 'Beta'},
|
|
227
|
+
{}
|
|
228
|
+
]);
|
|
229
|
+
mocks.appendChild(select);
|
|
230
|
+
|
|
231
|
+
setTimeout(() => {
|
|
232
|
+
try {
|
|
233
|
+
const options = select.getOption('options');
|
|
234
|
+
expect(options[0].value).to.equal('Alpha');
|
|
235
|
+
expect(options[0].label).to.equal('Alpha');
|
|
236
|
+
expect(options[0].visibility).to.equal('visible');
|
|
237
|
+
expect(options[1].value).to.equal('Beta');
|
|
238
|
+
expect(options[1].label).to.equal('Beta');
|
|
239
|
+
expect(options[1].visibility).to.equal('visible');
|
|
240
|
+
expect(options[2].value).to.be.a('string');
|
|
241
|
+
expect(options[2].label).to.equal(options[2].value);
|
|
242
|
+
expect(options[2].visibility).to.equal('visible');
|
|
243
|
+
} catch (e) {
|
|
244
|
+
return done(e);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
done();
|
|
248
|
+
}, 350);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('should not parse options arrays with multiple string entries', function (done) {
|
|
252
|
+
this.timeout(2000);
|
|
253
|
+
|
|
254
|
+
let mocks = document.getElementById('mocks');
|
|
255
|
+
const select = document.createElement('monster-select');
|
|
256
|
+
select.setOption('options', ['One', 'Two']);
|
|
257
|
+
mocks.appendChild(select);
|
|
258
|
+
|
|
259
|
+
setTimeout(() => {
|
|
260
|
+
try {
|
|
261
|
+
const options = select.getOption('options');
|
|
262
|
+
const error = select.getAttribute('data-monster-error') ?? '';
|
|
263
|
+
expect(error).to.not.contain('Unexpected token');
|
|
264
|
+
expect(options.length).to.equal(2);
|
|
265
|
+
expect(options[0]).to.equal('One');
|
|
266
|
+
expect(options[1]).to.equal('Two');
|
|
267
|
+
} catch (e) {
|
|
268
|
+
return done(e);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
done();
|
|
272
|
+
}, 350);
|
|
273
|
+
});
|
|
274
|
+
|
|
219
275
|
});
|
|
220
276
|
|
|
221
277
|
|
|
@@ -8,6 +8,7 @@ describe('RestAPI', function () {
|
|
|
8
8
|
|
|
9
9
|
let fetchReference;
|
|
10
10
|
let returnStatus;
|
|
11
|
+
let responseBody;
|
|
11
12
|
|
|
12
13
|
afterEach(() => {
|
|
13
14
|
globalThis['fetch'] = fetchReference;
|
|
@@ -16,6 +17,7 @@ describe('RestAPI', function () {
|
|
|
16
17
|
beforeEach(() => {
|
|
17
18
|
|
|
18
19
|
returnStatus = 200;
|
|
20
|
+
responseBody = JSON.stringify({a: "test"});
|
|
19
21
|
fetchReference = globalThis['fetch'];
|
|
20
22
|
globalThis['fetch'] = function (options) {
|
|
21
23
|
|
|
@@ -23,9 +25,7 @@ describe('RestAPI', function () {
|
|
|
23
25
|
resolve({
|
|
24
26
|
text: function () {
|
|
25
27
|
return new Promise((resolve, reject) => {
|
|
26
|
-
resolve(
|
|
27
|
-
a: "test"
|
|
28
|
-
}));
|
|
28
|
+
resolve(responseBody);
|
|
29
29
|
});
|
|
30
30
|
},
|
|
31
31
|
status: returnStatus
|
|
@@ -91,5 +91,42 @@ describe('RestAPI', function () {
|
|
|
91
91
|
|
|
92
92
|
})
|
|
93
93
|
|
|
94
|
+
describe('read response parsing', function () {
|
|
95
|
+
it('should reject on invalid json', function (done) {
|
|
96
|
+
responseBody = "{invalid";
|
|
97
|
+
const ds = new RestAPI({url: 'https://monsterjs.org/assets/world.json'})
|
|
98
|
+
ds.read().then(() => {
|
|
99
|
+
done("should not run.");
|
|
100
|
+
}).catch(() => done());
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should call responseCallback when provided', function (done) {
|
|
104
|
+
let called = false;
|
|
105
|
+
const ds = new RestAPI({
|
|
106
|
+
read: {
|
|
107
|
+
url: 'https://monsterjs.org/assets/world.json',
|
|
108
|
+
responseCallback: () => {
|
|
109
|
+
called = true;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
ds.read().then(() => {
|
|
114
|
+
expect(called).to.be.true;
|
|
115
|
+
done();
|
|
116
|
+
}).catch(e => done(e));
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe('getClone', function () {
|
|
121
|
+
it('should return an independent clone', function () {
|
|
122
|
+
const ds = new RestAPI({
|
|
123
|
+
read: {url: 'https://monsterjs.org/assets/world.json'},
|
|
124
|
+
write: {url: 'https://monsterjs.org/assets/world.json'}
|
|
125
|
+
});
|
|
126
|
+
const clone = ds.getClone();
|
|
127
|
+
clone.setOption('read.url', 'https://example.com/changed.json');
|
|
128
|
+
expect(ds.getOption('read.url')).to.equal('https://monsterjs.org/assets/world.json');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
94
131
|
|
|
95
132
|
})
|
|
@@ -2,11 +2,10 @@ import {expect} from "chai"
|
|
|
2
2
|
import {WebConnect} from "../../../../../source/data/datasource/server/webconnect.mjs";
|
|
3
3
|
import {initWebSocket} from "../../../../util/websocket.mjs";
|
|
4
4
|
|
|
5
|
-
const testUrl = "wss://ws.postman-echo.com/raw"
|
|
6
|
-
|
|
7
5
|
describe('Websocket', function () {
|
|
8
6
|
|
|
9
7
|
let ds = undefined
|
|
8
|
+
const testUrl = "ws://mock.local"
|
|
10
9
|
|
|
11
10
|
before(function (done) {
|
|
12
11
|
initWebSocket().then(() => {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import {expect} from "chai"
|
|
4
4
|
import {Datasource} from "../../../source/data/datasource.mjs";
|
|
5
|
+
import {DataUrl} from "../../../source/types/dataurl.mjs";
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
describe('Datasource', function () {
|
|
@@ -26,6 +27,25 @@ describe('Datasource', function () {
|
|
|
26
27
|
expect(datasource.getOption('default')).to.be.true
|
|
27
28
|
});
|
|
28
29
|
|
|
30
|
+
it('setOptions should parse json string', function () {
|
|
31
|
+
const datasource = new Datasource();
|
|
32
|
+
datasource.setOptions('{"default":true,"nested":{"flag":1}}');
|
|
33
|
+
expect(datasource.getOption('default')).to.be.true
|
|
34
|
+
expect(datasource.getOption('nested.flag')).to.be.equal(1)
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('setOptions should parse data url json', function () {
|
|
38
|
+
const datasource = new Datasource();
|
|
39
|
+
const dataUrl = new DataUrl('{"default":true}', 'application/json', false).toString();
|
|
40
|
+
datasource.setOptions(dataUrl);
|
|
41
|
+
expect(datasource.getOption('default')).to.be.true
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('setOptions should throw on invalid json string', function () {
|
|
45
|
+
const datasource = new Datasource();
|
|
46
|
+
expect(() => datasource.setOptions('{')).to.throw(Error);
|
|
47
|
+
});
|
|
48
|
+
|
|
29
49
|
})
|
|
30
50
|
|
|
31
51
|
describe('rw', function () {
|
|
@@ -57,4 +77,4 @@ describe('Datasource', function () {
|
|
|
57
77
|
})
|
|
58
78
|
|
|
59
79
|
|
|
60
|
-
})
|
|
80
|
+
})
|
|
@@ -402,7 +402,10 @@ describe('DOM', function () {
|
|
|
402
402
|
div.append(d);
|
|
403
403
|
|
|
404
404
|
|
|
405
|
-
|
|
405
|
+
const cssName = CSSStyleSheet?.name || "CSSStyleSheet";
|
|
406
|
+
expect(div).contain.html(
|
|
407
|
+
`data-monster-error="value is not an instance of ${cssName}"`,
|
|
408
|
+
);
|
|
406
409
|
done();
|
|
407
410
|
|
|
408
411
|
})
|
|
@@ -54,7 +54,7 @@ describe('Stylesheet', function () {
|
|
|
54
54
|
describe('External Stylesheet', () => {
|
|
55
55
|
|
|
56
56
|
let id = new ID('Stylesheet').toString();
|
|
57
|
-
let stylesheet, url = '
|
|
57
|
+
let stylesheet, url = new DataUrl('body{color:red;}', 'text/css').toString();
|
|
58
58
|
|
|
59
59
|
beforeEach(() => {
|
|
60
60
|
|
|
@@ -65,11 +65,20 @@ describe('Stylesheet', function () {
|
|
|
65
65
|
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
+
const triggerLoad = () => {
|
|
69
|
+
const link = document.getElementById(id);
|
|
70
|
+
if (link) {
|
|
71
|
+
link.dispatchEvent(new window.Event("load"));
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
68
75
|
it('append and remove Stylesheet ', (done) => {
|
|
69
76
|
|
|
70
77
|
expect(stylesheet.isConnected()).to.be.false;
|
|
71
78
|
|
|
72
|
-
stylesheet.connect()
|
|
79
|
+
stylesheet.connect();
|
|
80
|
+
triggerLoad();
|
|
81
|
+
stylesheet.available().then(() => {
|
|
73
82
|
expect(stylesheet.isConnected()).to.be.true;
|
|
74
83
|
expect(document.querySelector('[href="' + url + '"]')).to.exist;
|
|
75
84
|
|
|
@@ -77,7 +86,9 @@ describe('Stylesheet', function () {
|
|
|
77
86
|
expect(stylesheet.isConnected()).to.be.false;
|
|
78
87
|
expect(document.querySelector('[href="' + url + '"]')).not.to.exist;
|
|
79
88
|
|
|
80
|
-
stylesheet.connect()
|
|
89
|
+
stylesheet.connect();
|
|
90
|
+
triggerLoad();
|
|
91
|
+
stylesheet.available().then(() => {
|
|
81
92
|
expect(stylesheet.isConnected()).to.be.true;
|
|
82
93
|
expect(document.querySelector('[href="' + url + '"]')).to.exist;
|
|
83
94
|
|
|
@@ -98,4 +109,4 @@ describe('Stylesheet', function () {
|
|
|
98
109
|
});
|
|
99
110
|
|
|
100
111
|
|
|
101
|
-
});
|
|
112
|
+
});
|
|
@@ -51,7 +51,7 @@ describe('Link', function () {
|
|
|
51
51
|
this.timeout(5000);
|
|
52
52
|
|
|
53
53
|
let id = new ID('link').toString();
|
|
54
|
-
let link, url = '
|
|
54
|
+
let link, url = new DataUrl('body{color:red;}', 'text/css').toString();
|
|
55
55
|
|
|
56
56
|
beforeEach(() => {
|
|
57
57
|
|
|
@@ -63,11 +63,20 @@ describe('Link', function () {
|
|
|
63
63
|
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
+
const triggerLoad = () => {
|
|
67
|
+
const node = document.getElementById(id);
|
|
68
|
+
if (node) {
|
|
69
|
+
node.dispatchEvent(new window.Event("load"));
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
66
73
|
it('append and remove Link ', (done) => {
|
|
67
74
|
|
|
68
75
|
expect(link.isConnected()).to.be.false;
|
|
69
76
|
|
|
70
|
-
link.connect()
|
|
77
|
+
link.connect();
|
|
78
|
+
triggerLoad();
|
|
79
|
+
link.available().then(() => {
|
|
71
80
|
expect(link.isConnected()).to.be.true;
|
|
72
81
|
expect(document.querySelector('[href="' + url + '"]')).to.exist;
|
|
73
82
|
|
|
@@ -75,7 +84,9 @@ describe('Link', function () {
|
|
|
75
84
|
expect(link.isConnected()).to.be.false;
|
|
76
85
|
expect(document.querySelector('[href="' + url + '"]')).not.to.exist;
|
|
77
86
|
|
|
78
|
-
link.connect()
|
|
87
|
+
link.connect();
|
|
88
|
+
triggerLoad();
|
|
89
|
+
link.available().then(() => {
|
|
79
90
|
expect(link.isConnected()).to.be.true;
|
|
80
91
|
expect(document.querySelector('[href="' + url + '"]')).to.exist;
|
|
81
92
|
|
|
@@ -96,4 +107,4 @@ describe('Link', function () {
|
|
|
96
107
|
});
|
|
97
108
|
|
|
98
109
|
|
|
99
|
-
});
|
|
110
|
+
});
|
|
@@ -60,7 +60,7 @@ describe('Script', function () {
|
|
|
60
60
|
describe('External JS', () => {
|
|
61
61
|
|
|
62
62
|
let id = new ID('script').toString();
|
|
63
|
-
let server, script, url = '
|
|
63
|
+
let server, script, url = new DataUrl('console.log(1);', 'text/javascript').toString();
|
|
64
64
|
|
|
65
65
|
beforeEach(() => {
|
|
66
66
|
|
|
@@ -79,11 +79,20 @@ describe('Script', function () {
|
|
|
79
79
|
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
+
const triggerLoad = () => {
|
|
83
|
+
const node = document.getElementById(id);
|
|
84
|
+
if (node) {
|
|
85
|
+
node.dispatchEvent(new window.Event("load"));
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
82
89
|
it('append and remove script ', (done) => {
|
|
83
90
|
|
|
84
91
|
expect(script.isConnected()).to.be.false;
|
|
85
92
|
|
|
86
|
-
script.connect()
|
|
93
|
+
script.connect();
|
|
94
|
+
triggerLoad();
|
|
95
|
+
script.available().then(() => {
|
|
87
96
|
expect(script.isConnected()).to.be.true;
|
|
88
97
|
expect(document.querySelector('[src="' + url + '"]')).to.exist;
|
|
89
98
|
|
|
@@ -91,7 +100,9 @@ describe('Script', function () {
|
|
|
91
100
|
expect(script.isConnected()).to.be.false;
|
|
92
101
|
expect(document.querySelector('[src="' + url + '"]')).not.to.exist;
|
|
93
102
|
|
|
94
|
-
script.connect()
|
|
103
|
+
script.connect();
|
|
104
|
+
triggerLoad();
|
|
105
|
+
script.available().then(() => {
|
|
95
106
|
expect(script.isConnected()).to.be.true;
|
|
96
107
|
expect(document.querySelector('[src="' + url + '"]')).to.exist;
|
|
97
108
|
|
|
@@ -112,4 +123,4 @@ describe('Script', function () {
|
|
|
112
123
|
});
|
|
113
124
|
|
|
114
125
|
|
|
115
|
-
});
|
|
126
|
+
});
|
|
@@ -926,4 +926,33 @@ describe("DOM", function () {
|
|
|
926
926
|
});
|
|
927
927
|
});
|
|
928
928
|
});
|
|
929
|
+
|
|
930
|
+
describe("Updater reactive updates", function () {
|
|
931
|
+
it("should update the DOM when the subject changes", function (done) {
|
|
932
|
+
let mocks = document.getElementById("mocks");
|
|
933
|
+
mocks.innerHTML = html1;
|
|
934
|
+
|
|
935
|
+
const element = document.getElementById("test1");
|
|
936
|
+
const updater = new Updater(element, { a: { b: ["one"] } });
|
|
937
|
+
|
|
938
|
+
updater
|
|
939
|
+
.run()
|
|
940
|
+
.then(() => {
|
|
941
|
+
expect(element).contain.html("one");
|
|
942
|
+
|
|
943
|
+
const subject = updater.getSubject();
|
|
944
|
+
subject.a.b = ["two"];
|
|
945
|
+
|
|
946
|
+
setTimeout(() => {
|
|
947
|
+
try {
|
|
948
|
+
expect(element).contain.html("two");
|
|
949
|
+
done();
|
|
950
|
+
} catch (e) {
|
|
951
|
+
done(e);
|
|
952
|
+
}
|
|
953
|
+
}, 50);
|
|
954
|
+
})
|
|
955
|
+
.catch((e) => done(e));
|
|
956
|
+
});
|
|
957
|
+
});
|
|
929
958
|
});
|
package/test/cases/monster.mjs
CHANGED
|
@@ -230,4 +230,35 @@ describe('ProxyObserver', function () {
|
|
|
230
230
|
});
|
|
231
231
|
});
|
|
232
232
|
|
|
233
|
+
describe('deleteProperty', function () {
|
|
234
|
+
it('should notify observers when deleting a key', function (done) {
|
|
235
|
+
const proxy = new ProxyObserver({a: 1});
|
|
236
|
+
const observer = new Observer(function () {
|
|
237
|
+
expect(proxy.getRealSubject()).to.eql({});
|
|
238
|
+
done();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
proxy.attachObserver(observer);
|
|
242
|
+
delete proxy.getSubject().a;
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
describe('symbol properties', function () {
|
|
247
|
+
it('should not notify observers for symbol keys', function (done) {
|
|
248
|
+
const proxy = new ProxyObserver({});
|
|
249
|
+
let called = false;
|
|
250
|
+
const observer = new Observer(function () {
|
|
251
|
+
called = true;
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
proxy.attachObserver(observer);
|
|
255
|
+
proxy.getSubject()[Symbol("hidden")] = "value";
|
|
256
|
+
|
|
257
|
+
setTimeout(() => {
|
|
258
|
+
expect(called).to.be.false;
|
|
259
|
+
done();
|
|
260
|
+
}, 0);
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
233
264
|
})
|
package/test/util/jsdom.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import {extend} from "../../source/data/extend.mjs";
|
|
4
4
|
import {getGlobal} from "../../source/types/global.mjs";
|
|
5
|
+
import {ResizeObserverMock} from "./resize-observer.mjs";
|
|
5
6
|
|
|
6
7
|
export const isBrowser = new Function("try {return this===window;}catch(e){ return false;}");
|
|
7
8
|
export const isNode = new Function("try {return this===global;}catch(e){return false;}");
|
|
@@ -24,7 +25,8 @@ function initJSDOM(options) {
|
|
|
24
25
|
includeNodeLocations: true,
|
|
25
26
|
storageQuota: 10000000,
|
|
26
27
|
runScripts: "dangerously",
|
|
27
|
-
resources: "usable"
|
|
28
|
+
resources: "usable",
|
|
29
|
+
url: "https://example.test/"
|
|
28
30
|
}, options || {})
|
|
29
31
|
|
|
30
32
|
return import("jsdom").then(({JSDOM}) => {
|
|
@@ -84,13 +86,46 @@ function initJSDOM(options) {
|
|
|
84
86
|
}
|
|
85
87
|
});
|
|
86
88
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
if (!window.ResizeObserver) {
|
|
90
|
+
window.ResizeObserver = ResizeObserverMock;
|
|
91
|
+
}
|
|
92
|
+
if (!g.ResizeObserver) {
|
|
93
|
+
g.ResizeObserver = window.ResizeObserver;
|
|
94
|
+
}
|
|
91
95
|
|
|
92
|
-
|
|
93
|
-
|
|
96
|
+
import("dom-storage").then(({default: Storage}) => {
|
|
97
|
+
const ensureStorage = (key) => {
|
|
98
|
+
let existing = null;
|
|
99
|
+
try {
|
|
100
|
+
existing = window[key];
|
|
101
|
+
} catch (e) {}
|
|
102
|
+
|
|
103
|
+
if (existing) {
|
|
104
|
+
g[key] = existing;
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const storage = new Storage(null, {strict: true});
|
|
109
|
+
const descriptor = Object.getOwnPropertyDescriptor(window, key);
|
|
110
|
+
|
|
111
|
+
if (!descriptor || descriptor.writable || typeof descriptor.set === "function") {
|
|
112
|
+
window[key] = storage;
|
|
113
|
+
} else if (descriptor.configurable === true) {
|
|
114
|
+
Object.defineProperty(window, key, {
|
|
115
|
+
value: storage,
|
|
116
|
+
configurable: true,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
g[key] = window[key] ?? storage;
|
|
122
|
+
} catch (e) {
|
|
123
|
+
g[key] = storage;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
ensureStorage("localStorage");
|
|
128
|
+
ensureStorage("sessionStorage");
|
|
94
129
|
|
|
95
130
|
resolve(g);
|
|
96
131
|
|
|
@@ -107,4 +142,3 @@ function initJSDOM(options) {
|
|
|
107
142
|
}
|
|
108
143
|
|
|
109
144
|
export {initJSDOM, JSDOMExport}
|
|
110
|
-
|
package/test/util/websocket.mjs
CHANGED
|
@@ -2,28 +2,48 @@ import {getGlobal} from "../../source/types/global.mjs";
|
|
|
2
2
|
|
|
3
3
|
function initWebSocket() {
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
class MockWebSocket {
|
|
6
|
+
constructor(url) {
|
|
7
|
+
this.url = url;
|
|
8
|
+
this.readyState = 0;
|
|
9
|
+
setTimeout(() => {
|
|
10
|
+
this.readyState = 1;
|
|
11
|
+
if (typeof this.onopen === "function") {
|
|
12
|
+
this.onopen();
|
|
13
|
+
}
|
|
14
|
+
}, 0);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
send(data) {
|
|
18
|
+
if (this.readyState !== 1) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
setTimeout(() => {
|
|
22
|
+
if (typeof this.onmessage === "function") {
|
|
23
|
+
this.onmessage({data});
|
|
24
|
+
}
|
|
25
|
+
}, 0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
close() {
|
|
29
|
+
if (this.readyState === 3) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
this.readyState = 3;
|
|
33
|
+
if (typeof this.onclose === "function") {
|
|
34
|
+
this.onclose({code: 1000});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
8
37
|
|
|
9
|
-
|
|
10
|
-
|
|
38
|
+
terminate() {
|
|
39
|
+
this.close();
|
|
40
|
+
}
|
|
11
41
|
}
|
|
12
42
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
constructor(url, protocols) {
|
|
16
|
-
super(url, protocols, {
|
|
17
|
-
handshakeTimeout: 1000,
|
|
18
|
-
maxPayload: 1024 * 1024 * 1024,
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
});
|
|
43
|
+
getGlobal().WebSocket = MockWebSocket;
|
|
44
|
+
return Promise.resolve();
|
|
25
45
|
|
|
26
46
|
|
|
27
47
|
}
|
|
28
48
|
|
|
29
|
-
export {initWebSocket}
|
|
49
|
+
export {initWebSocket}
|
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.70.
|
|
13
|
-
<div id="lastupdate" style='font-size:0.7em'>last update Sa 3. Jan
|
|
12
|
+
<h1 style='margin-bottom: 0.1em;'>Monster 4.70.1</h1>
|
|
13
|
+
<div id="lastupdate" style='font-size:0.7em'>last update Sa 3. Jan 13:33:23 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>
|