@schukai/monster 4.148.3 → 4.148.4
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
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.6"},"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.148.
|
|
1
|
+
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.6"},"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.148.4"}
|
|
@@ -113,6 +113,18 @@ const keyFilterEventSymbol = Symbol("keyFilterEvent");
|
|
|
113
113
|
*/
|
|
114
114
|
const lazyLoadDoneSymbol = Symbol("lazyLoadDone");
|
|
115
115
|
|
|
116
|
+
/**
|
|
117
|
+
* @private
|
|
118
|
+
* @type {Symbol}
|
|
119
|
+
*/
|
|
120
|
+
const lazyLoadRequestSymbol = Symbol("lazyLoadRequest");
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @private
|
|
124
|
+
* @type {Symbol}
|
|
125
|
+
*/
|
|
126
|
+
const lazyLoadErrorSymbol = Symbol("lazyLoadError");
|
|
127
|
+
|
|
116
128
|
/**
|
|
117
129
|
* @private
|
|
118
130
|
* @type {Symbol}
|
|
@@ -300,6 +312,7 @@ const optionsMapVersionSnapshotSymbol = Symbol("optionsMapVersionSnapshot");
|
|
|
300
312
|
const selectionVersionSymbol = Symbol("selectionVersion");
|
|
301
313
|
const closeOnSelectAutoSymbol = Symbol("closeOnSelectAuto");
|
|
302
314
|
const lastFilterValueSymbol = Symbol("lastFilterValue");
|
|
315
|
+
const filterInputVersionSymbol = Symbol("filterInputVersion");
|
|
303
316
|
|
|
304
317
|
/**
|
|
305
318
|
* @private
|
|
@@ -2051,6 +2064,7 @@ function invalidatePendingRemoteWork() {
|
|
|
2051
2064
|
}
|
|
2052
2065
|
this[isLoadingSymbol] = false;
|
|
2053
2066
|
this[remoteInfoRequestSymbol] = null;
|
|
2067
|
+
delete this[lazyLoadRequestSymbol];
|
|
2054
2068
|
|
|
2055
2069
|
if (this[keyFilterEventSymbol] instanceof DeadMansSwitch) {
|
|
2056
2070
|
try {
|
|
@@ -4014,6 +4028,7 @@ function handleFilterInputEvents() {
|
|
|
4014
4028
|
}
|
|
4015
4029
|
|
|
4016
4030
|
this[lastFilterValueSymbol] = filterValue;
|
|
4031
|
+
bumpFilterInputVersion.call(this);
|
|
4017
4032
|
|
|
4018
4033
|
if (this[keyFilterEventSymbol] instanceof DeadMansSwitch) {
|
|
4019
4034
|
try {
|
|
@@ -4061,6 +4076,16 @@ function getCurrentFilterInputValue() {
|
|
|
4061
4076
|
return undefined;
|
|
4062
4077
|
}
|
|
4063
4078
|
|
|
4079
|
+
function getFilterInputVersion() {
|
|
4080
|
+
return Number.isInteger(this[filterInputVersionSymbol])
|
|
4081
|
+
? this[filterInputVersionSymbol]
|
|
4082
|
+
: 0;
|
|
4083
|
+
}
|
|
4084
|
+
|
|
4085
|
+
function bumpFilterInputVersion() {
|
|
4086
|
+
this[filterInputVersionSymbol] = getFilterInputVersion.call(this) + 1;
|
|
4087
|
+
}
|
|
4088
|
+
|
|
4064
4089
|
/**
|
|
4065
4090
|
* @private
|
|
4066
4091
|
*/
|
|
@@ -4601,7 +4626,15 @@ function areOptionsAvailableAndInitInternal() {
|
|
|
4601
4626
|
options === null ||
|
|
4602
4627
|
(isArray(options) && options.length === 0)
|
|
4603
4628
|
) {
|
|
4604
|
-
|
|
4629
|
+
const lazyLoadPending = this[lazyLoadRequestSymbol] instanceof Promise;
|
|
4630
|
+
const lazyLoadError = isString(this[lazyLoadErrorSymbol]);
|
|
4631
|
+
if (lazyLoadError) {
|
|
4632
|
+
setStatusOrRemoveBadges.call(this, "error");
|
|
4633
|
+
} else if (lazyLoadPending) {
|
|
4634
|
+
setStatusOrRemoveBadges.call(this, "loading");
|
|
4635
|
+
} else {
|
|
4636
|
+
setStatusOrRemoveBadges.call(this, "empty");
|
|
4637
|
+
}
|
|
4605
4638
|
if (getFilterMode.call(this) === FILTER_MODE_REMOTE) {
|
|
4606
4639
|
if (this[isLoadingSymbol] !== true) {
|
|
4607
4640
|
if (isInteger(this.getOption("total"))) {
|
|
@@ -4615,7 +4648,9 @@ function areOptionsAvailableAndInitInternal() {
|
|
|
4615
4648
|
|
|
4616
4649
|
let msg = this.getOption("labels.no-options-available");
|
|
4617
4650
|
|
|
4618
|
-
if (
|
|
4651
|
+
if (lazyLoadError) {
|
|
4652
|
+
msg = this.getOption("labels.cannot-be-loaded");
|
|
4653
|
+
} else if (
|
|
4619
4654
|
this.getOption("url") !== null &&
|
|
4620
4655
|
this.getOption("features.lazyLoad") === true &&
|
|
4621
4656
|
this[lazyLoadDoneSymbol] !== true
|
|
@@ -4651,7 +4686,11 @@ function areOptionsAvailableAndInitInternal() {
|
|
|
4651
4686
|
if (this.getOption("features.emptyValueIfNoOptions") === true) {
|
|
4652
4687
|
this.value = "";
|
|
4653
4688
|
}
|
|
4654
|
-
if (
|
|
4689
|
+
if (
|
|
4690
|
+
this[isLoadingSymbol] !== true &&
|
|
4691
|
+
lazyLoadPending === false &&
|
|
4692
|
+
lazyLoadError === false
|
|
4693
|
+
) {
|
|
4655
4694
|
addErrorAttribute(this, "No options available.");
|
|
4656
4695
|
}
|
|
4657
4696
|
return false;
|
|
@@ -5087,24 +5126,65 @@ function show() {
|
|
|
5087
5126
|
this.getOption("features.lazyLoad") && this[lazyLoadDoneSymbol] !== true;
|
|
5088
5127
|
|
|
5089
5128
|
if (lazyLoadFlag === true) {
|
|
5090
|
-
this[
|
|
5129
|
+
if (this[lazyLoadRequestSymbol] instanceof Promise) {
|
|
5130
|
+
return;
|
|
5131
|
+
}
|
|
5132
|
+
|
|
5133
|
+
if (isString(this[lazyLoadErrorSymbol])) {
|
|
5134
|
+
removeErrorAttribute(this, this[lazyLoadErrorSymbol]);
|
|
5135
|
+
delete this[lazyLoadErrorSymbol];
|
|
5136
|
+
}
|
|
5137
|
+
removeErrorAttribute(this, "No options available.");
|
|
5091
5138
|
setStatusOrRemoveBadges.call(this, "loading");
|
|
5092
5139
|
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5140
|
+
const lifecycleVersion = getRemoteLifecycleVersion.call(this);
|
|
5141
|
+
const lazyLoadRequest = new Processing(200, () => {
|
|
5142
|
+
if (
|
|
5143
|
+
!isRemoteLifecycleCurrent.call(this, lifecycleVersion) ||
|
|
5144
|
+
this.isConnected !== true
|
|
5145
|
+
) {
|
|
5146
|
+
return;
|
|
5147
|
+
}
|
|
5148
|
+
|
|
5149
|
+
return this.fetch();
|
|
5150
|
+
}).run();
|
|
5151
|
+
this[lazyLoadRequestSymbol] = lazyLoadRequest;
|
|
5152
|
+
|
|
5153
|
+
lazyLoadRequest
|
|
5154
|
+
.then(() => {
|
|
5155
|
+
if (
|
|
5156
|
+
this[lazyLoadRequestSymbol] !== lazyLoadRequest ||
|
|
5157
|
+
!isRemoteLifecycleCurrent.call(this, lifecycleVersion) ||
|
|
5158
|
+
this.isConnected !== true
|
|
5159
|
+
) {
|
|
5160
|
+
return;
|
|
5161
|
+
}
|
|
5162
|
+
|
|
5163
|
+
delete this[lazyLoadRequestSymbol];
|
|
5164
|
+
this[lazyLoadDoneSymbol] = true;
|
|
5165
|
+
delete this[lazyLoadErrorSymbol];
|
|
5166
|
+
checkOptionState.call(this);
|
|
5167
|
+
requestAnimationFrame(() => {
|
|
5168
|
+
if (
|
|
5169
|
+
isRemoteLifecycleCurrent.call(this, lifecycleVersion) &&
|
|
5170
|
+
this.isConnected === true
|
|
5171
|
+
) {
|
|
5098
5172
|
show.call(this);
|
|
5099
|
-
}
|
|
5100
|
-
})
|
|
5101
|
-
.catch((e) => {
|
|
5102
|
-
addErrorAttribute(this, e);
|
|
5103
|
-
setStatusOrRemoveBadges.call(this, "error");
|
|
5173
|
+
}
|
|
5104
5174
|
});
|
|
5105
|
-
|
|
5106
|
-
.run()
|
|
5175
|
+
})
|
|
5107
5176
|
.catch((e) => {
|
|
5177
|
+
if (
|
|
5178
|
+
this[lazyLoadRequestSymbol] !== lazyLoadRequest ||
|
|
5179
|
+
!isRemoteLifecycleCurrent.call(this, lifecycleVersion)
|
|
5180
|
+
) {
|
|
5181
|
+
return;
|
|
5182
|
+
}
|
|
5183
|
+
|
|
5184
|
+
delete this[lazyLoadRequestSymbol];
|
|
5185
|
+
this[lazyLoadDoneSymbol] = false;
|
|
5186
|
+
this[lazyLoadErrorSymbol] =
|
|
5187
|
+
e instanceof Error ? e.message : String(e);
|
|
5108
5188
|
addErrorAttribute(this, e);
|
|
5109
5189
|
setStatusOrRemoveBadges.call(this, "error");
|
|
5110
5190
|
});
|
|
@@ -5141,6 +5221,8 @@ function show() {
|
|
|
5141
5221
|
addAttributeToken(this[controlElementSymbol], "class", "open");
|
|
5142
5222
|
registerWithHost.call(this);
|
|
5143
5223
|
|
|
5224
|
+
const filterInputVersion = getFilterInputVersion.call(this);
|
|
5225
|
+
|
|
5144
5226
|
new Processing(() => {
|
|
5145
5227
|
const shouldLoadRemoteOptions =
|
|
5146
5228
|
getFilterMode.call(self) === FILTER_MODE_REMOTE &&
|
|
@@ -5152,12 +5234,18 @@ function show() {
|
|
|
5152
5234
|
|
|
5153
5235
|
if (shouldLoadDefaultOptions) {
|
|
5154
5236
|
setTimeout(() => {
|
|
5237
|
+
if (getFilterInputVersion.call(this) !== filterInputVersion) {
|
|
5238
|
+
return;
|
|
5239
|
+
}
|
|
5155
5240
|
loadDefaultOptionsFromUrl.call(self).catch((e) => {
|
|
5156
5241
|
addErrorAttribute(self, e);
|
|
5157
5242
|
});
|
|
5158
5243
|
}, 0);
|
|
5159
5244
|
} else if (shouldLoadRemoteOptions) {
|
|
5160
5245
|
setTimeout(() => {
|
|
5246
|
+
if (getFilterInputVersion.call(this) !== filterInputVersion) {
|
|
5247
|
+
return;
|
|
5248
|
+
}
|
|
5161
5249
|
self[cleanupOptionsListSymbol] = true;
|
|
5162
5250
|
filterFromRemote.call(self).catch((e) => {
|
|
5163
5251
|
addErrorAttribute(self, e);
|
|
@@ -97,6 +97,14 @@ function configureRemotePaginatedSelect(select) {
|
|
|
97
97
|
select.setOption('mapping.objectsPerPage', 'pagination.perPage');
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
function configureLazySelect(select) {
|
|
101
|
+
select.setOption('url', 'https://example.com/lazy-options');
|
|
102
|
+
select.setOption('features.lazyLoad', true);
|
|
103
|
+
select.setOption('mapping.selector', 'items.*');
|
|
104
|
+
select.setOption('mapping.labelTemplate', '${name}');
|
|
105
|
+
select.setOption('mapping.valueTemplate', '${id}');
|
|
106
|
+
}
|
|
107
|
+
|
|
100
108
|
let Select,
|
|
101
109
|
SelectStyleSheet,
|
|
102
110
|
getDefaultSelectPopperPositionProfile,
|
|
@@ -643,6 +651,223 @@ describe('Select', function () {
|
|
|
643
651
|
|
|
644
652
|
});
|
|
645
653
|
|
|
654
|
+
describe('Lazy load lifecycle', function () {
|
|
655
|
+
this.timeout(5000);
|
|
656
|
+
|
|
657
|
+
afterEach(() => {
|
|
658
|
+
const mocks = document.getElementById('mocks');
|
|
659
|
+
mocks.innerHTML = '';
|
|
660
|
+
global['fetch'] = fetchReference;
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
it('should open from the first click after a delayed lazy response renders', async function () {
|
|
664
|
+
const deferredResponse = createDeferred();
|
|
665
|
+
let requestCount = 0;
|
|
666
|
+
global['fetch'] = function () {
|
|
667
|
+
requestCount += 1;
|
|
668
|
+
return deferredResponse.promise;
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
const mocks = document.getElementById('mocks');
|
|
672
|
+
const select = document.createElement('monster-select');
|
|
673
|
+
configureLazySelect(select);
|
|
674
|
+
mocks.appendChild(select);
|
|
675
|
+
|
|
676
|
+
await waitForCondition(() => {
|
|
677
|
+
return select.shadowRoot.querySelector('[data-monster-role=container]') instanceof HTMLElement;
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
const container = select.shadowRoot.querySelector('[data-monster-role=container]');
|
|
681
|
+
const popper = select.shadowRoot.querySelector('[data-monster-role=popper]');
|
|
682
|
+
container.click();
|
|
683
|
+
|
|
684
|
+
await waitForCondition(() => requestCount === 1);
|
|
685
|
+
container.click();
|
|
686
|
+
await new Promise(resolve => setTimeout(resolve, 250));
|
|
687
|
+
expect(requestCount).to.equal(1);
|
|
688
|
+
deferredResponse.resolve(
|
|
689
|
+
await createJsonResponse({
|
|
690
|
+
items: [{id: 'alpha', name: 'Alpha'}]
|
|
691
|
+
})
|
|
692
|
+
);
|
|
693
|
+
|
|
694
|
+
await waitForCondition(() => {
|
|
695
|
+
return select.shadowRoot.querySelectorAll('[data-monster-role=option]').length === 1;
|
|
696
|
+
});
|
|
697
|
+
await waitForCondition(() => popper.style.display === 'block');
|
|
698
|
+
|
|
699
|
+
expect(requestCount).to.equal(1);
|
|
700
|
+
expect(popper.style.display).to.equal('block');
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
it('should keep a failed lazy load in the error state', async function () {
|
|
704
|
+
let requestCount = 0;
|
|
705
|
+
global['fetch'] = function () {
|
|
706
|
+
requestCount += 1;
|
|
707
|
+
return createJsonResponse({}, 500);
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
const mocks = document.getElementById('mocks');
|
|
711
|
+
const select = document.createElement('monster-select');
|
|
712
|
+
configureLazySelect(select);
|
|
713
|
+
mocks.appendChild(select);
|
|
714
|
+
|
|
715
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
716
|
+
select.shadowRoot.querySelector('[data-monster-role=container]').click();
|
|
717
|
+
|
|
718
|
+
await waitForCondition(() => requestCount === 1);
|
|
719
|
+
await waitForCondition(() => {
|
|
720
|
+
return (select.getAttribute('data-monster-error') ?? '').includes('HTTP error! status: 500');
|
|
721
|
+
});
|
|
722
|
+
await new Promise(resolve => setTimeout(resolve, 350));
|
|
723
|
+
|
|
724
|
+
expect(select.getOption('classes.statusOrRemoveBadge')).to.equal('error');
|
|
725
|
+
expect(select.getAttribute('data-monster-error')).to.not.contain('No options available.');
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
it('should retry a failed lazy load on the next click', async function () {
|
|
729
|
+
let requestCount = 0;
|
|
730
|
+
global['fetch'] = function () {
|
|
731
|
+
requestCount += 1;
|
|
732
|
+
if (requestCount === 1) {
|
|
733
|
+
return createJsonResponse({}, 500);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
return createJsonResponse({
|
|
737
|
+
items: [{id: 'alpha', name: 'Alpha'}]
|
|
738
|
+
});
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
const mocks = document.getElementById('mocks');
|
|
742
|
+
const select = document.createElement('monster-select');
|
|
743
|
+
configureLazySelect(select);
|
|
744
|
+
mocks.appendChild(select);
|
|
745
|
+
|
|
746
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
747
|
+
const container = select.shadowRoot.querySelector('[data-monster-role=container]');
|
|
748
|
+
const popper = select.shadowRoot.querySelector('[data-monster-role=popper]');
|
|
749
|
+
container.click();
|
|
750
|
+
|
|
751
|
+
await waitForCondition(() => requestCount === 1);
|
|
752
|
+
await waitForCondition(() => {
|
|
753
|
+
return (select.getAttribute('data-monster-error') ?? '').includes('HTTP error! status: 500');
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
container.click();
|
|
757
|
+
|
|
758
|
+
await waitForCondition(() => requestCount === 2, {timeout: 1500});
|
|
759
|
+
await waitForCondition(() => {
|
|
760
|
+
return select.shadowRoot.querySelectorAll('[data-monster-role=option]').length === 1;
|
|
761
|
+
});
|
|
762
|
+
await waitForCondition(() => popper.style.display === 'block');
|
|
763
|
+
|
|
764
|
+
expect(requestCount).to.equal(2);
|
|
765
|
+
expect(select.getAttribute('data-monster-error') ?? '').to.not.contain('HTTP error! status: 500');
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
it('should retry lazy loading after disconnecting during the request', async function () {
|
|
769
|
+
const firstResponse = createDeferred();
|
|
770
|
+
let requestCount = 0;
|
|
771
|
+
global['fetch'] = function () {
|
|
772
|
+
requestCount += 1;
|
|
773
|
+
if (requestCount === 1) {
|
|
774
|
+
return firstResponse.promise;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
return createJsonResponse({
|
|
778
|
+
items: [{id: 'fresh', name: 'Fresh'}]
|
|
779
|
+
});
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
const mocks = document.getElementById('mocks');
|
|
783
|
+
const select = document.createElement('monster-select');
|
|
784
|
+
configureLazySelect(select);
|
|
785
|
+
mocks.appendChild(select);
|
|
786
|
+
|
|
787
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
788
|
+
const container = select.shadowRoot.querySelector('[data-monster-role=container]');
|
|
789
|
+
container.click();
|
|
790
|
+
await waitForCondition(() => requestCount === 1);
|
|
791
|
+
|
|
792
|
+
select.remove();
|
|
793
|
+
mocks.appendChild(select);
|
|
794
|
+
firstResponse.resolve(
|
|
795
|
+
await createJsonResponse({
|
|
796
|
+
items: [{id: 'stale', name: 'Stale'}]
|
|
797
|
+
})
|
|
798
|
+
);
|
|
799
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
800
|
+
|
|
801
|
+
container.click();
|
|
802
|
+
|
|
803
|
+
await waitForCondition(() => requestCount === 2, {timeout: 1500});
|
|
804
|
+
await waitForCondition(() => {
|
|
805
|
+
return select.getOption('options').map(option => option.value).includes('fresh');
|
|
806
|
+
});
|
|
807
|
+
expect(select.getOption('options').map(option => option.value)).to.deep.equal(['fresh']);
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
it('should not start a delayed lazy request after disconnecting', async function () {
|
|
811
|
+
let requestCount = 0;
|
|
812
|
+
global['fetch'] = function () {
|
|
813
|
+
requestCount += 1;
|
|
814
|
+
return createJsonResponse({
|
|
815
|
+
items: [{id: 'fresh', name: 'Fresh'}]
|
|
816
|
+
});
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
const mocks = document.getElementById('mocks');
|
|
820
|
+
const select = document.createElement('monster-select');
|
|
821
|
+
configureLazySelect(select);
|
|
822
|
+
mocks.appendChild(select);
|
|
823
|
+
|
|
824
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
825
|
+
const container = select.shadowRoot.querySelector('[data-monster-role=container]');
|
|
826
|
+
container.click();
|
|
827
|
+
select.remove();
|
|
828
|
+
|
|
829
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
830
|
+
expect(requestCount).to.equal(0);
|
|
831
|
+
|
|
832
|
+
mocks.appendChild(select);
|
|
833
|
+
container.click();
|
|
834
|
+
await waitForCondition(() => requestCount === 1);
|
|
835
|
+
await waitForCondition(() => {
|
|
836
|
+
return select.getOption('options').map(option => option.value).includes('fresh');
|
|
837
|
+
});
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
it('should not reload a completed lazy select after reconnecting', async function () {
|
|
841
|
+
let requestCount = 0;
|
|
842
|
+
global['fetch'] = function () {
|
|
843
|
+
requestCount += 1;
|
|
844
|
+
return createJsonResponse({
|
|
845
|
+
items: [{id: 'alpha', name: 'Alpha'}]
|
|
846
|
+
});
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
const mocks = document.getElementById('mocks');
|
|
850
|
+
const select = document.createElement('monster-select');
|
|
851
|
+
configureLazySelect(select);
|
|
852
|
+
mocks.appendChild(select);
|
|
853
|
+
|
|
854
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
855
|
+
const container = select.shadowRoot.querySelector('[data-monster-role=container]');
|
|
856
|
+
const popper = select.shadowRoot.querySelector('[data-monster-role=popper]');
|
|
857
|
+
container.click();
|
|
858
|
+
await waitForCondition(() => popper.style.display === 'block');
|
|
859
|
+
|
|
860
|
+
container.click();
|
|
861
|
+
await waitForCondition(() => popper.style.display === 'none');
|
|
862
|
+
select.remove();
|
|
863
|
+
mocks.appendChild(select);
|
|
864
|
+
container.click();
|
|
865
|
+
await waitForCondition(() => popper.style.display === 'block');
|
|
866
|
+
|
|
867
|
+
expect(requestCount).to.equal(1);
|
|
868
|
+
});
|
|
869
|
+
});
|
|
870
|
+
|
|
646
871
|
describe('Popper sizing', function () {
|
|
647
872
|
this.timeout(5000);
|
|
648
873
|
|
|
@@ -1701,6 +1926,56 @@ describe('Select', function () {
|
|
|
1701
1926
|
});
|
|
1702
1927
|
});
|
|
1703
1928
|
|
|
1929
|
+
describe('Remote open lifecycle', function () {
|
|
1930
|
+
this.timeout(5000);
|
|
1931
|
+
|
|
1932
|
+
afterEach(() => {
|
|
1933
|
+
const mocks = document.getElementById('mocks');
|
|
1934
|
+
mocks.innerHTML = '';
|
|
1935
|
+
global['fetch'] = fetchReference;
|
|
1936
|
+
});
|
|
1937
|
+
|
|
1938
|
+
it('should request an immediately entered remote filter only once', async function () {
|
|
1939
|
+
const requests = [];
|
|
1940
|
+
global['fetch'] = function (url) {
|
|
1941
|
+
requests.push(String(url));
|
|
1942
|
+
return createJsonResponse({
|
|
1943
|
+
items: [{id: 'alpha', name: 'Alpha'}]
|
|
1944
|
+
});
|
|
1945
|
+
};
|
|
1946
|
+
|
|
1947
|
+
const mocks = document.getElementById('mocks');
|
|
1948
|
+
const select = document.createElement('monster-select');
|
|
1949
|
+
select.setOption('url', 'https://example.com/items?filter={filter}&page={page}');
|
|
1950
|
+
select.setOption('filter.mode', 'remote');
|
|
1951
|
+
select.setOption('filter.position', 'popper');
|
|
1952
|
+
select.setOption('mapping.selector', 'items.*');
|
|
1953
|
+
select.setOption('mapping.labelTemplate', '${name}');
|
|
1954
|
+
select.setOption('mapping.valueTemplate', '${id}');
|
|
1955
|
+
mocks.appendChild(select);
|
|
1956
|
+
|
|
1957
|
+
await waitForCondition(() => {
|
|
1958
|
+
return select.shadowRoot.querySelector('[data-monster-role=filter][name="popper-filter"]') instanceof HTMLInputElement;
|
|
1959
|
+
});
|
|
1960
|
+
|
|
1961
|
+
const container = select.shadowRoot.querySelector('[data-monster-role=container]');
|
|
1962
|
+
const filterInput = select.shadowRoot.querySelector('[data-monster-role=filter][name="popper-filter"]');
|
|
1963
|
+
container.click();
|
|
1964
|
+
filterInput.value = 'alpha';
|
|
1965
|
+
filterInput.dispatchEvent(new Event('input', {
|
|
1966
|
+
bubbles: true,
|
|
1967
|
+
composed: true
|
|
1968
|
+
}));
|
|
1969
|
+
|
|
1970
|
+
await waitForCondition(() => requests.length >= 1);
|
|
1971
|
+
await new Promise(resolve => setTimeout(resolve, 350));
|
|
1972
|
+
|
|
1973
|
+
expect(requests).to.deep.equal([
|
|
1974
|
+
'https://example.com/items?filter=alpha&page=1'
|
|
1975
|
+
]);
|
|
1976
|
+
});
|
|
1977
|
+
});
|
|
1978
|
+
|
|
1704
1979
|
describe('document.createElement()', function () {
|
|
1705
1980
|
|
|
1706
1981
|
afterEach(() => {
|