@dile/crud 2.1.12 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/ajax-select-crud/__screenshots__/ajax-select-crud-overlay.spec.js/dile-ajax-select-crud-overlay-Selecting-a-result--no-extra-click-required--opens-the-popup-as-soon-as-results-load-and-lets-the-user-pick-without-a-second-click-1.png +0 -0
- package/components/ajax-select-crud/__screenshots__/ajax-select-crud-overlay.spec.js/dile-ajax-select-crud-overlay-Uses-axios-instead-of-fetch-fetches-the-initial-value-display-text-through-axios-1.png +0 -0
- package/components/ajax-select-crud/__screenshots__/ajax-select-crud-overlay.spec.js/dile-ajax-select-crud-overlay-Uses-axios-instead-of-fetch-requests-through-window-axiosInstance-get--not-the-native-fetch-API-1.png +0 -0
- package/components/ajax-select-crud/__screenshots__/zzdebug.spec.js/debug-debug-opened-timing-1.png +0 -0
- package/components/ajax-select-crud/ajax-select-crud-overlay.js +5 -0
- package/components/ajax-select-crud/ajax-select-crud-overlay.spec.js +166 -0
- package/components/ajax-select-crud/index.js +2 -1
- package/components/ajax-select-crud/src/DileAjaxSelectCrudOverlay.js +80 -0
- package/package.json +3 -3
package/components/ajax-select-crud/__screenshots__/zzdebug.spec.js/debug-debug-opened-timing-1.png
ADDED
|
Binary file
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { describe, it, expect, afterEach, vi } from 'vitest';
|
|
2
|
+
import './ajax-select-crud-overlay.js';
|
|
3
|
+
|
|
4
|
+
describe('dile-ajax-select-crud-overlay', () => {
|
|
5
|
+
afterEach(() => {
|
|
6
|
+
document.body.innerHTML = '';
|
|
7
|
+
delete window.axiosInstance;
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
function wait(ms) {
|
|
11
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function mockAxios(responseData) {
|
|
15
|
+
const get = vi.fn(() => Promise.resolve({ status: 200, data: responseData }));
|
|
16
|
+
window.axiosInstance = { get };
|
|
17
|
+
return get;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function renderCrudSelect(html) {
|
|
21
|
+
document.body.innerHTML = html;
|
|
22
|
+
const el = document.body.querySelector('dile-ajax-select-crud-overlay');
|
|
23
|
+
await el.updateComplete;
|
|
24
|
+
return el;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function typeKeyword(el, keyword) {
|
|
28
|
+
const input = el.shadowRoot.getElementById('search');
|
|
29
|
+
input.value = keyword;
|
|
30
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
31
|
+
await wait(el.delay + 50);
|
|
32
|
+
await el.updateComplete;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe('Rendering', () => {
|
|
36
|
+
it('renders the search input, same as dile-select-ajax-overlay', async () => {
|
|
37
|
+
mockAxios([]);
|
|
38
|
+
const el = await renderCrudSelect(`
|
|
39
|
+
<dile-ajax-select-crud-overlay endpoint="/api/countries" idProperty="id" displayProperty="name"></dile-ajax-select-crud-overlay>
|
|
40
|
+
`);
|
|
41
|
+
|
|
42
|
+
const input = el.shadowRoot.getElementById('search');
|
|
43
|
+
expect(input).toBeTruthy();
|
|
44
|
+
expect(input.getAttribute('role')).toBe('combobox');
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe('Uses axios instead of fetch', () => {
|
|
49
|
+
it('requests through window.axiosInstance.get, not the native fetch API', async () => {
|
|
50
|
+
const get = mockAxios([{ id: 1, name: 'Spain' }]);
|
|
51
|
+
const fetchSpy = vi.spyOn(window, 'fetch');
|
|
52
|
+
|
|
53
|
+
const el = await renderCrudSelect(`
|
|
54
|
+
<dile-ajax-select-crud-overlay endpoint="/api/countries" idProperty="id" displayProperty="name" queryStringVariable="keyword" delay="10"></dile-ajax-select-crud-overlay>
|
|
55
|
+
`);
|
|
56
|
+
|
|
57
|
+
await typeKeyword(el, 'sp');
|
|
58
|
+
|
|
59
|
+
expect(get).toHaveBeenCalledWith('/api/countries', { params: { keyword: 'sp' } });
|
|
60
|
+
expect(fetchSpy).not.toHaveBeenCalled();
|
|
61
|
+
expect(el.data.length).toBe(1);
|
|
62
|
+
expect(el.select.opened).toBe(true);
|
|
63
|
+
|
|
64
|
+
fetchSpy.mockRestore();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('fetches the initial value display text through axios', async () => {
|
|
68
|
+
// searchValueInitial() passes response.data (i.e. the "data" envelope, not the raw
|
|
69
|
+
// response) down to registerText(), matching dile-ajax-select-crud's own convention.
|
|
70
|
+
const get = vi.fn(() => Promise.resolve({ status: 200, data: { data: { name: 'Spain' } } }));
|
|
71
|
+
window.axiosInstance = { get };
|
|
72
|
+
|
|
73
|
+
const el = await renderCrudSelect(`
|
|
74
|
+
<dile-ajax-select-crud-overlay endpoint="/api/countries" idProperty="id" displayProperty="name" value="22"></dile-ajax-select-crud-overlay>
|
|
75
|
+
`);
|
|
76
|
+
await wait(50);
|
|
77
|
+
await el.updateComplete;
|
|
78
|
+
|
|
79
|
+
expect(get).toHaveBeenCalledWith('/api/countries/22');
|
|
80
|
+
expect(el.selectedText).toBe('Spain');
|
|
81
|
+
expect(el.isSelected).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('Selecting a result (no extra click required)', () => {
|
|
86
|
+
it('opens the popup as soon as results load and lets the user pick without a second click', async () => {
|
|
87
|
+
mockAxios([{ id: 1, name: 'Spain' }, { id: 2, name: 'France' }]);
|
|
88
|
+
const el = await renderCrudSelect(`
|
|
89
|
+
<dile-ajax-select-crud-overlay endpoint="/api/countries" idProperty="id" displayProperty="name" delay="10"></dile-ajax-select-crud-overlay>
|
|
90
|
+
`);
|
|
91
|
+
|
|
92
|
+
await typeKeyword(el, 'sp');
|
|
93
|
+
expect(el.select.opened).toBe(true);
|
|
94
|
+
|
|
95
|
+
const options = el.select.shadowRoot.querySelectorAll('[role="option"]');
|
|
96
|
+
options[0].click();
|
|
97
|
+
await el.select.updateComplete;
|
|
98
|
+
await el.updateComplete;
|
|
99
|
+
|
|
100
|
+
expect(el.value).toBe('1');
|
|
101
|
+
expect(el.selectedText).toBe('Spain');
|
|
102
|
+
expect(el.isSelected).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe('maxResults / pageParamName', () => {
|
|
107
|
+
it('adds the page-size param to the request when both are set', async () => {
|
|
108
|
+
const get = mockAxios([]);
|
|
109
|
+
const el = await renderCrudSelect(`
|
|
110
|
+
<dile-ajax-select-crud-overlay endpoint="/api/countries" idProperty="id" displayProperty="name" queryStringVariable="keyword" maxResults="5" pageParamName="limit" delay="10"></dile-ajax-select-crud-overlay>
|
|
111
|
+
`);
|
|
112
|
+
|
|
113
|
+
await typeKeyword(el, 'sp');
|
|
114
|
+
|
|
115
|
+
expect(get).toHaveBeenCalledWith('/api/countries', { params: { keyword: 'sp', limit: 5 } });
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('omits the page-size param when pageParamName is not set', async () => {
|
|
119
|
+
const get = mockAxios([]);
|
|
120
|
+
const el = await renderCrudSelect(`
|
|
121
|
+
<dile-ajax-select-crud-overlay endpoint="/api/countries" idProperty="id" displayProperty="name" queryStringVariable="keyword" maxResults="5" delay="10"></dile-ajax-select-crud-overlay>
|
|
122
|
+
`);
|
|
123
|
+
|
|
124
|
+
await typeKeyword(el, 'sp');
|
|
125
|
+
|
|
126
|
+
expect(get).toHaveBeenCalledWith('/api/countries', { params: { keyword: 'sp' } });
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe('getSelectResultList', () => {
|
|
131
|
+
it('uses getSelectResultList to extract the list when the response shape needs adapting', async () => {
|
|
132
|
+
mockAxios({ data: { result: { data: [{ id: 1, name: 'Spain' }] } } });
|
|
133
|
+
const el = await renderCrudSelect(`
|
|
134
|
+
<dile-ajax-select-crud-overlay endpoint="/api/countries" idProperty="id" displayProperty="name" delay="10"></dile-ajax-select-crud-overlay>
|
|
135
|
+
`);
|
|
136
|
+
el.getSelectResultList = (response) => response.data.result.data;
|
|
137
|
+
|
|
138
|
+
await typeKeyword(el, 'sp');
|
|
139
|
+
|
|
140
|
+
expect(el.data).toEqual([{ id: 1, name: 'Spain' }]);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('takes priority over resultDataProperty when both are set', async () => {
|
|
144
|
+
mockAxios({ items: [{ id: 1, name: 'Spain' }], data: [] });
|
|
145
|
+
const el = await renderCrudSelect(`
|
|
146
|
+
<dile-ajax-select-crud-overlay endpoint="/api/countries" idProperty="id" displayProperty="name" resultDataProperty="data" delay="10"></dile-ajax-select-crud-overlay>
|
|
147
|
+
`);
|
|
148
|
+
el.getSelectResultList = (response) => response.items;
|
|
149
|
+
|
|
150
|
+
await typeKeyword(el, 'sp');
|
|
151
|
+
|
|
152
|
+
expect(el.data).toEqual([{ id: 1, name: 'Spain' }]);
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
describe('Form Association', () => {
|
|
157
|
+
it('is form-associated, same as dile-select-ajax-overlay', async () => {
|
|
158
|
+
mockAxios([]);
|
|
159
|
+
const el = await renderCrudSelect(`
|
|
160
|
+
<dile-ajax-select-crud-overlay endpoint="/api/countries" idProperty="id" displayProperty="name"></dile-ajax-select-crud-overlay>
|
|
161
|
+
`);
|
|
162
|
+
|
|
163
|
+
expect(el.internals).toBeTruthy();
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export { DileAjaxSelectCrud } from './src/DileAjaxSelectCrud.js';
|
|
1
|
+
export { DileAjaxSelectCrud } from './src/DileAjaxSelectCrud.js';
|
|
2
|
+
export { DileAjaxSelectCrudOverlay } from './src/DileAjaxSelectCrudOverlay.js';
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { DileAxios } from '../../../lib/DileAxios.js';
|
|
2
|
+
import { DileSelectAjaxOverlay } from '@dile/ui/components/select/index.js';
|
|
3
|
+
|
|
4
|
+
export class DileAjaxSelectCrudOverlay extends DileAxios(DileSelectAjaxOverlay) {
|
|
5
|
+
|
|
6
|
+
static get properties() {
|
|
7
|
+
return {
|
|
8
|
+
maxResults: { type: Number },
|
|
9
|
+
pageParamName: { type: String },
|
|
10
|
+
getSelectResultList: { type: Object },
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
searchValueInitial() {
|
|
19
|
+
let request = this.axiosInstance.get(`${this.endpoint}/${this.value}`);
|
|
20
|
+
request.then((response) => {
|
|
21
|
+
if (response.status == 200) {
|
|
22
|
+
let res = response.data;
|
|
23
|
+
if (res.error) {
|
|
24
|
+
this.registerError(res.data);
|
|
25
|
+
} else {
|
|
26
|
+
this.registerText(res.data);
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
this.registerError('Bad response code');
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
.catch(err => {
|
|
33
|
+
this.registerError(err);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
loadData() {
|
|
38
|
+
this.loading = true;
|
|
39
|
+
let params = this.additionalQueryString || {};
|
|
40
|
+
if (this.pageParamName && this.maxResults) {
|
|
41
|
+
params[this.pageParamName] = this.maxResults;
|
|
42
|
+
}
|
|
43
|
+
params[this.queryStringVariable] = this.keyword;
|
|
44
|
+
let request = this.axiosInstance.get(this.endpoint, { params });
|
|
45
|
+
request.then((response) => {
|
|
46
|
+
if (response.status == 200) {
|
|
47
|
+
let res = response.data;
|
|
48
|
+
if (res.error) {
|
|
49
|
+
this.registerError(res.data);
|
|
50
|
+
} else {
|
|
51
|
+
this.registerData(res);
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
this.registerError('Bad response code');
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
.catch(err => {
|
|
58
|
+
this.registerError(err);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
registerText(json) {
|
|
63
|
+
this.selectedText = json[this.displayProperty];
|
|
64
|
+
this.loading = false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
registerData(json) {
|
|
68
|
+
if(this.getSelectResultList) {
|
|
69
|
+
this.data = this.getSelectResultList(json);
|
|
70
|
+
} else {
|
|
71
|
+
this.data = this.getResultData(json);
|
|
72
|
+
}
|
|
73
|
+
this.updateComplete.then(() => {
|
|
74
|
+
this.loading = false;
|
|
75
|
+
if (this.keyword.length > 0 && this.data.length > 0) {
|
|
76
|
+
this.select?.open();
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dile/crud",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Components to create a generic crud system based on Web Components and Lit",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
},
|
|
26
26
|
"homepage": "https://dile-components.com/",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@dile/ui": "^3.
|
|
28
|
+
"@dile/ui": "^3.5.0",
|
|
29
29
|
"axios": "^1.19.0",
|
|
30
30
|
"lit": "^2.7.0 || ^3.0.0"
|
|
31
31
|
},
|
|
32
32
|
"publishConfig": {
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "817f0dfc3c345957ae7a63c113e22aa0f80a773f"
|
|
36
36
|
}
|